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