1 /*
2 * the plpy module
3 *
4 * src/pl/plpython/plpy_plpymodule.c
5 */
6
7 #include "postgres.h"
8
9 #include "access/xact.h"
10 #include "mb/pg_wchar.h"
11 #include "utils/builtins.h"
12 #include "utils/snapmgr.h"
13
14 #include "plpython.h"
15
16 #include "plpy_plpymodule.h"
17
18 #include "plpy_cursorobject.h"
19 #include "plpy_elog.h"
20 #include "plpy_main.h"
21 #include "plpy_planobject.h"
22 #include "plpy_resultobject.h"
23 #include "plpy_spi.h"
24 #include "plpy_subxactobject.h"
25
26
27 HTAB *PLy_spi_exceptions = NULL;
28
29
30 static void PLy_add_exceptions(PyObject *plpy);
31 static PyObject *PLy_create_exception(char *name,
32 PyObject *base, PyObject *dict,
33 const char *modname, PyObject *mod);
34 static void PLy_generate_spi_exceptions(PyObject *mod, PyObject *base);
35
36 /* module functions */
37 static PyObject *PLy_debug(PyObject *self, PyObject *args, PyObject *kw);
38 static PyObject *PLy_log(PyObject *self, PyObject *args, PyObject *kw);
39 static PyObject *PLy_info(PyObject *self, PyObject *args, PyObject *kw);
40 static PyObject *PLy_notice(PyObject *self, PyObject *args, PyObject *kw);
41 static PyObject *PLy_warning(PyObject *self, PyObject *args, PyObject *kw);
42 static PyObject *PLy_error(PyObject *self, PyObject *args, PyObject *kw);
43 static PyObject *PLy_fatal(PyObject *self, PyObject *args, PyObject *kw);
44 static PyObject *PLy_quote_literal(PyObject *self, PyObject *args);
45 static PyObject *PLy_quote_nullable(PyObject *self, PyObject *args);
46 static PyObject *PLy_quote_ident(PyObject *self, PyObject *args);
47 static PyObject *PLy_commit(PyObject *self, PyObject *args);
48 static PyObject *PLy_rollback(PyObject *self, PyObject *args);
49
50
51 /* A list of all known exceptions, generated from backend/utils/errcodes.txt */
52 typedef struct ExceptionMap
53 {
54 char *name;
55 char *classname;
56 int sqlstate;
57 } ExceptionMap;
58
59 static const ExceptionMap exception_map[] = {
60 #include "spiexceptions.h"
61 {NULL, NULL, 0}
62 };
63
64 static PyMethodDef PLy_methods[] = {
65 /*
66 * logging methods
67 */
68 {"debug", (PyCFunction) PLy_debug, METH_VARARGS | METH_KEYWORDS, NULL},
69 {"log", (PyCFunction) PLy_log, METH_VARARGS | METH_KEYWORDS, NULL},
70 {"info", (PyCFunction) PLy_info, METH_VARARGS | METH_KEYWORDS, NULL},
71 {"notice", (PyCFunction) PLy_notice, METH_VARARGS | METH_KEYWORDS, NULL},
72 {"warning", (PyCFunction) PLy_warning, METH_VARARGS | METH_KEYWORDS, NULL},
73 {"error", (PyCFunction) PLy_error, METH_VARARGS | METH_KEYWORDS, NULL},
74 {"fatal", (PyCFunction) PLy_fatal, METH_VARARGS | METH_KEYWORDS, NULL},
75
76 /*
77 * create a stored plan
78 */
79 {"prepare", PLy_spi_prepare, METH_VARARGS, NULL},
80
81 /*
82 * execute a plan or query
83 */
84 {"execute", PLy_spi_execute, METH_VARARGS, NULL},
85
86 /*
87 * escaping strings
88 */
89 {"quote_literal", PLy_quote_literal, METH_VARARGS, NULL},
90 {"quote_nullable", PLy_quote_nullable, METH_VARARGS, NULL},
91 {"quote_ident", PLy_quote_ident, METH_VARARGS, NULL},
92
93 /*
94 * create the subtransaction context manager
95 */
96 {"subtransaction", PLy_subtransaction_new, METH_NOARGS, NULL},
97
98 /*
99 * create a cursor
100 */
101 {"cursor", PLy_cursor, METH_VARARGS, NULL},
102
103 /*
104 * transaction control
105 */
106 {"commit", PLy_commit, METH_NOARGS, NULL},
107 {"rollback", PLy_rollback, METH_NOARGS, NULL},
108
109 {NULL, NULL, 0, NULL}
110 };
111
112 static PyMethodDef PLy_exc_methods[] = {
113 {NULL, NULL, 0, NULL}
114 };
115
116 #if PY_MAJOR_VERSION >= 3
117 static PyModuleDef PLy_module = {
118 PyModuleDef_HEAD_INIT, /* m_base */
119 "plpy", /* m_name */
120 NULL, /* m_doc */
121 -1, /* m_size */
122 PLy_methods, /* m_methods */
123 };
124
125 static PyModuleDef PLy_exc_module = {
126 PyModuleDef_HEAD_INIT, /* m_base */
127 "spiexceptions", /* m_name */
128 NULL, /* m_doc */
129 -1, /* m_size */
130 PLy_exc_methods, /* m_methods */
131 NULL, /* m_reload */
132 NULL, /* m_traverse */
133 NULL, /* m_clear */
134 NULL /* m_free */
135 };
136
137 /*
138 * Must have external linkage, because PyMODINIT_FUNC does dllexport on
139 * Windows-like platforms.
140 */
141 PyMODINIT_FUNC
PyInit_plpy(void)142 PyInit_plpy(void)
143 {
144 PyObject *m;
145
146 m = PyModule_Create(&PLy_module);
147 if (m == NULL)
148 return NULL;
149
150 PLy_add_exceptions(m);
151
152 return m;
153 }
154 #endif /* PY_MAJOR_VERSION >= 3 */
155
156 void
PLy_init_plpy(void)157 PLy_init_plpy(void)
158 {
159 PyObject *main_mod,
160 *main_dict,
161 *plpy_mod;
162
163 #if PY_MAJOR_VERSION < 3
164 PyObject *plpy;
165 #endif
166
167 /*
168 * initialize plpy module
169 */
170 PLy_plan_init_type();
171 PLy_result_init_type();
172 PLy_subtransaction_init_type();
173 PLy_cursor_init_type();
174
175 #if PY_MAJOR_VERSION >= 3
176 PyModule_Create(&PLy_module);
177 /* for Python 3 we initialized the exceptions in PyInit_plpy */
178 #else
179 plpy = Py_InitModule("plpy", PLy_methods);
180 PLy_add_exceptions(plpy);
181 #endif
182
183 /* PyDict_SetItemString(plpy, "PlanType", (PyObject *) &PLy_PlanType); */
184
185 /*
186 * initialize main module, and add plpy
187 */
188 main_mod = PyImport_AddModule("__main__");
189 main_dict = PyModule_GetDict(main_mod);
190 plpy_mod = PyImport_AddModule("plpy");
191 if (plpy_mod == NULL)
192 PLy_elog(ERROR, "could not import \"plpy\" module");
193 PyDict_SetItemString(main_dict, "plpy", plpy_mod);
194 if (PyErr_Occurred())
195 PLy_elog(ERROR, "could not import \"plpy\" module");
196 }
197
198 static void
PLy_add_exceptions(PyObject * plpy)199 PLy_add_exceptions(PyObject *plpy)
200 {
201 PyObject *excmod;
202 HASHCTL hash_ctl;
203
204 #if PY_MAJOR_VERSION < 3
205 excmod = Py_InitModule("spiexceptions", PLy_exc_methods);
206 #else
207 excmod = PyModule_Create(&PLy_exc_module);
208 #endif
209 if (excmod == NULL)
210 PLy_elog(ERROR, "could not create the spiexceptions module");
211
212 /*
213 * PyModule_AddObject does not add a refcount to the object, for some odd
214 * reason; we must do that.
215 */
216 Py_INCREF(excmod);
217 if (PyModule_AddObject(plpy, "spiexceptions", excmod) < 0)
218 PLy_elog(ERROR, "could not add the spiexceptions module");
219
220 PLy_exc_error = PLy_create_exception("plpy.Error", NULL, NULL,
221 "Error", plpy);
222 PLy_exc_fatal = PLy_create_exception("plpy.Fatal", NULL, NULL,
223 "Fatal", plpy);
224 PLy_exc_spi_error = PLy_create_exception("plpy.SPIError", NULL, NULL,
225 "SPIError", plpy);
226
227 memset(&hash_ctl, 0, sizeof(hash_ctl));
228 hash_ctl.keysize = sizeof(int);
229 hash_ctl.entrysize = sizeof(PLyExceptionEntry);
230 PLy_spi_exceptions = hash_create("PL/Python SPI exceptions", 256,
231 &hash_ctl, HASH_ELEM | HASH_BLOBS);
232
233 PLy_generate_spi_exceptions(excmod, PLy_exc_spi_error);
234 }
235
236 /*
237 * Create an exception object and add it to the module
238 */
239 static PyObject *
PLy_create_exception(char * name,PyObject * base,PyObject * dict,const char * modname,PyObject * mod)240 PLy_create_exception(char *name, PyObject *base, PyObject *dict,
241 const char *modname, PyObject *mod)
242 {
243 PyObject *exc;
244
245 exc = PyErr_NewException(name, base, dict);
246 if (exc == NULL)
247 PLy_elog(ERROR, NULL);
248
249 /*
250 * PyModule_AddObject does not add a refcount to the object, for some odd
251 * reason; we must do that.
252 */
253 Py_INCREF(exc);
254 PyModule_AddObject(mod, modname, exc);
255
256 /*
257 * The caller will also store a pointer to the exception object in some
258 * permanent variable, so add another ref to account for that. This is
259 * probably excessively paranoid, but let's be sure.
260 */
261 Py_INCREF(exc);
262 return exc;
263 }
264
265 /*
266 * Add all the autogenerated exceptions as subclasses of SPIError
267 */
268 static void
PLy_generate_spi_exceptions(PyObject * mod,PyObject * base)269 PLy_generate_spi_exceptions(PyObject *mod, PyObject *base)
270 {
271 int i;
272
273 for (i = 0; exception_map[i].name != NULL; i++)
274 {
275 bool found;
276 PyObject *exc;
277 PLyExceptionEntry *entry;
278 PyObject *sqlstate;
279 PyObject *dict = PyDict_New();
280
281 if (dict == NULL)
282 PLy_elog(ERROR, NULL);
283
284 sqlstate = PyString_FromString(unpack_sql_state(exception_map[i].sqlstate));
285 if (sqlstate == NULL)
286 PLy_elog(ERROR, "could not generate SPI exceptions");
287
288 PyDict_SetItemString(dict, "sqlstate", sqlstate);
289 Py_DECREF(sqlstate);
290
291 exc = PLy_create_exception(exception_map[i].name, base, dict,
292 exception_map[i].classname, mod);
293
294 entry = hash_search(PLy_spi_exceptions, &exception_map[i].sqlstate,
295 HASH_ENTER, &found);
296 Assert(!found);
297 entry->exc = exc;
298 }
299 }
300
301
302 /*
303 * the python interface to the elog function
304 * don't confuse these with PLy_elog
305 */
306 static PyObject *PLy_output(volatile int level, PyObject *self,
307 PyObject *args, PyObject *kw);
308
309 static PyObject *
PLy_debug(PyObject * self,PyObject * args,PyObject * kw)310 PLy_debug(PyObject *self, PyObject *args, PyObject *kw)
311 {
312 return PLy_output(DEBUG2, self, args, kw);
313 }
314
315 static PyObject *
PLy_log(PyObject * self,PyObject * args,PyObject * kw)316 PLy_log(PyObject *self, PyObject *args, PyObject *kw)
317 {
318 return PLy_output(LOG, self, args, kw);
319 }
320
321 static PyObject *
PLy_info(PyObject * self,PyObject * args,PyObject * kw)322 PLy_info(PyObject *self, PyObject *args, PyObject *kw)
323 {
324 return PLy_output(INFO, self, args, kw);
325 }
326
327 static PyObject *
PLy_notice(PyObject * self,PyObject * args,PyObject * kw)328 PLy_notice(PyObject *self, PyObject *args, PyObject *kw)
329 {
330 return PLy_output(NOTICE, self, args, kw);
331 }
332
333 static PyObject *
PLy_warning(PyObject * self,PyObject * args,PyObject * kw)334 PLy_warning(PyObject *self, PyObject *args, PyObject *kw)
335 {
336 return PLy_output(WARNING, self, args, kw);
337 }
338
339 static PyObject *
PLy_error(PyObject * self,PyObject * args,PyObject * kw)340 PLy_error(PyObject *self, PyObject *args, PyObject *kw)
341 {
342 return PLy_output(ERROR, self, args, kw);
343 }
344
345 static PyObject *
PLy_fatal(PyObject * self,PyObject * args,PyObject * kw)346 PLy_fatal(PyObject *self, PyObject *args, PyObject *kw)
347 {
348 return PLy_output(FATAL, self, args, kw);
349 }
350
351 static PyObject *
PLy_quote_literal(PyObject * self,PyObject * args)352 PLy_quote_literal(PyObject *self, PyObject *args)
353 {
354 const char *str;
355 char *quoted;
356 PyObject *ret;
357
358 if (!PyArg_ParseTuple(args, "s:quote_literal", &str))
359 return NULL;
360
361 quoted = quote_literal_cstr(str);
362 ret = PyString_FromString(quoted);
363 pfree(quoted);
364
365 return ret;
366 }
367
368 static PyObject *
PLy_quote_nullable(PyObject * self,PyObject * args)369 PLy_quote_nullable(PyObject *self, PyObject *args)
370 {
371 const char *str;
372 char *quoted;
373 PyObject *ret;
374
375 if (!PyArg_ParseTuple(args, "z:quote_nullable", &str))
376 return NULL;
377
378 if (str == NULL)
379 return PyString_FromString("NULL");
380
381 quoted = quote_literal_cstr(str);
382 ret = PyString_FromString(quoted);
383 pfree(quoted);
384
385 return ret;
386 }
387
388 static PyObject *
PLy_quote_ident(PyObject * self,PyObject * args)389 PLy_quote_ident(PyObject *self, PyObject *args)
390 {
391 const char *str;
392 const char *quoted;
393 PyObject *ret;
394
395 if (!PyArg_ParseTuple(args, "s:quote_ident", &str))
396 return NULL;
397
398 quoted = quote_identifier(str);
399 ret = PyString_FromString(quoted);
400
401 return ret;
402 }
403
404 /* enforce cast of object to string */
405 static char *
object_to_string(PyObject * obj)406 object_to_string(PyObject *obj)
407 {
408 if (obj)
409 {
410 PyObject *so = PyObject_Str(obj);
411
412 if (so != NULL)
413 {
414 char *str;
415
416 str = pstrdup(PyString_AsString(so));
417 Py_DECREF(so);
418
419 return str;
420 }
421 }
422
423 return NULL;
424 }
425
426 static PyObject *
PLy_output(volatile int level,PyObject * self,PyObject * args,PyObject * kw)427 PLy_output(volatile int level, PyObject *self, PyObject *args, PyObject *kw)
428 {
429 int sqlstate = 0;
430 char *volatile sqlstatestr = NULL;
431 char *volatile message = NULL;
432 char *volatile detail = NULL;
433 char *volatile hint = NULL;
434 char *volatile column_name = NULL;
435 char *volatile constraint_name = NULL;
436 char *volatile datatype_name = NULL;
437 char *volatile table_name = NULL;
438 char *volatile schema_name = NULL;
439 volatile MemoryContext oldcontext;
440 PyObject *key,
441 *value;
442 PyObject *volatile so;
443 Py_ssize_t pos = 0;
444
445 if (PyTuple_Size(args) == 1)
446 {
447 /*
448 * Treat single argument specially to avoid undesirable ('tuple',)
449 * decoration.
450 */
451 PyObject *o;
452
453 if (!PyArg_UnpackTuple(args, "plpy.elog", 1, 1, &o))
454 PLy_elog(ERROR, "could not unpack arguments in plpy.elog");
455 so = PyObject_Str(o);
456 }
457 else
458 so = PyObject_Str(args);
459
460 if (so == NULL || ((message = PyString_AsString(so)) == NULL))
461 {
462 level = ERROR;
463 message = dgettext(TEXTDOMAIN, "could not parse error message in plpy.elog");
464 }
465 message = pstrdup(message);
466
467 Py_XDECREF(so);
468
469 if (kw != NULL)
470 {
471 while (PyDict_Next(kw, &pos, &key, &value))
472 {
473 char *keyword = PyString_AsString(key);
474
475 if (strcmp(keyword, "message") == 0)
476 {
477 /* the message should not be overwritten */
478 if (PyTuple_Size(args) != 0)
479 {
480 PLy_exception_set(PyExc_TypeError, "argument 'message' given by name and position");
481 return NULL;
482 }
483
484 if (message)
485 pfree(message);
486 message = object_to_string(value);
487 }
488 else if (strcmp(keyword, "detail") == 0)
489 detail = object_to_string(value);
490 else if (strcmp(keyword, "hint") == 0)
491 hint = object_to_string(value);
492 else if (strcmp(keyword, "sqlstate") == 0)
493 sqlstatestr = object_to_string(value);
494 else if (strcmp(keyword, "schema_name") == 0)
495 schema_name = object_to_string(value);
496 else if (strcmp(keyword, "table_name") == 0)
497 table_name = object_to_string(value);
498 else if (strcmp(keyword, "column_name") == 0)
499 column_name = object_to_string(value);
500 else if (strcmp(keyword, "datatype_name") == 0)
501 datatype_name = object_to_string(value);
502 else if (strcmp(keyword, "constraint_name") == 0)
503 constraint_name = object_to_string(value);
504 else
505 {
506 PLy_exception_set(PyExc_TypeError,
507 "'%s' is an invalid keyword argument for this function",
508 keyword);
509 return NULL;
510 }
511 }
512 }
513
514 if (sqlstatestr != NULL)
515 {
516 if (strlen(sqlstatestr) != 5)
517 {
518 PLy_exception_set(PyExc_ValueError, "invalid SQLSTATE code");
519 return NULL;
520 }
521
522 if (strspn(sqlstatestr, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != 5)
523 {
524 PLy_exception_set(PyExc_ValueError, "invalid SQLSTATE code");
525 return NULL;
526 }
527
528 sqlstate = MAKE_SQLSTATE(sqlstatestr[0],
529 sqlstatestr[1],
530 sqlstatestr[2],
531 sqlstatestr[3],
532 sqlstatestr[4]);
533 }
534
535 oldcontext = CurrentMemoryContext;
536 PG_TRY();
537 {
538 if (message != NULL)
539 pg_verifymbstr(message, strlen(message), false);
540 if (detail != NULL)
541 pg_verifymbstr(detail, strlen(detail), false);
542 if (hint != NULL)
543 pg_verifymbstr(hint, strlen(hint), false);
544 if (schema_name != NULL)
545 pg_verifymbstr(schema_name, strlen(schema_name), false);
546 if (table_name != NULL)
547 pg_verifymbstr(table_name, strlen(table_name), false);
548 if (column_name != NULL)
549 pg_verifymbstr(column_name, strlen(column_name), false);
550 if (datatype_name != NULL)
551 pg_verifymbstr(datatype_name, strlen(datatype_name), false);
552 if (constraint_name != NULL)
553 pg_verifymbstr(constraint_name, strlen(constraint_name), false);
554
555 ereport(level,
556 ((sqlstate != 0) ? errcode(sqlstate) : 0,
557 (message != NULL) ? errmsg_internal("%s", message) : 0,
558 (detail != NULL) ? errdetail_internal("%s", detail) : 0,
559 (hint != NULL) ? errhint("%s", hint) : 0,
560 (column_name != NULL) ?
561 err_generic_string(PG_DIAG_COLUMN_NAME, column_name) : 0,
562 (constraint_name != NULL) ?
563 err_generic_string(PG_DIAG_CONSTRAINT_NAME, constraint_name) : 0,
564 (datatype_name != NULL) ?
565 err_generic_string(PG_DIAG_DATATYPE_NAME, datatype_name) : 0,
566 (table_name != NULL) ?
567 err_generic_string(PG_DIAG_TABLE_NAME, table_name) : 0,
568 (schema_name != NULL) ?
569 err_generic_string(PG_DIAG_SCHEMA_NAME, schema_name) : 0));
570 }
571 PG_CATCH();
572 {
573 ErrorData *edata;
574
575 MemoryContextSwitchTo(oldcontext);
576 edata = CopyErrorData();
577 FlushErrorState();
578
579 PLy_exception_set_with_details(PLy_exc_error, edata);
580 FreeErrorData(edata);
581
582 return NULL;
583 }
584 PG_END_TRY();
585
586 /*
587 * return a legal object so the interpreter will continue on its merry way
588 */
589 Py_RETURN_NONE;
590 }
591
592 static PyObject *
PLy_commit(PyObject * self,PyObject * args)593 PLy_commit(PyObject *self, PyObject *args)
594 {
595 PLyExecutionContext *exec_ctx = PLy_current_execution_context();
596
597 SPI_commit();
598 SPI_start_transaction();
599
600 /* was cleared at transaction end, reset pointer */
601 exec_ctx->scratch_ctx = NULL;
602
603 Py_RETURN_NONE;
604 }
605
606 static PyObject *
PLy_rollback(PyObject * self,PyObject * args)607 PLy_rollback(PyObject *self, PyObject *args)
608 {
609 PLyExecutionContext *exec_ctx = PLy_current_execution_context();
610
611 SPI_rollback();
612 SPI_start_transaction();
613
614 /* was cleared at transaction end, reset pointer */
615 exec_ctx->scratch_ctx = NULL;
616
617 Py_RETURN_NONE;
618 }
619