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