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