diff options
Diffstat (limited to 'src/pl/plpython/plpy_plpymodule.c')
-rw-r--r-- | src/pl/plpython/plpy_plpymodule.c | 206 |
1 files changed, 159 insertions, 47 deletions
diff --git a/src/pl/plpython/plpy_plpymodule.c b/src/pl/plpython/plpy_plpymodule.c index a44b7fbe9a3..f136e8ece8b 100644 --- a/src/pl/plpython/plpy_plpymodule.c +++ b/src/pl/plpython/plpy_plpymodule.c @@ -28,13 +28,13 @@ static void PLy_add_exceptions(PyObject *plpy); static void PLy_generate_spi_exceptions(PyObject *mod, PyObject *base); /* module functions */ -static PyObject *PLy_debug(PyObject *self, PyObject *args); -static PyObject *PLy_log(PyObject *self, PyObject *args); -static PyObject *PLy_info(PyObject *self, PyObject *args); -static PyObject *PLy_notice(PyObject *self, PyObject *args); -static PyObject *PLy_warning(PyObject *self, PyObject *args); -static PyObject *PLy_error(PyObject *self, PyObject *args); -static PyObject *PLy_fatal(PyObject *self, PyObject *args); +static PyObject *PLy_debug(PyObject *self, PyObject *args, PyObject *kw); +static PyObject *PLy_log(PyObject *self, PyObject *args, PyObject *kw); +static PyObject *PLy_info(PyObject *self, PyObject *args, PyObject *kw); +static PyObject *PLy_notice(PyObject *self, PyObject *args, PyObject *kw); +static PyObject *PLy_warning(PyObject *self, PyObject *args, PyObject *kw); +static PyObject *PLy_error(PyObject *self, PyObject *args, PyObject *kw); +static PyObject *PLy_fatal(PyObject *self, PyObject *args, PyObject *kw); static PyObject *PLy_quote_literal(PyObject *self, PyObject *args); static PyObject *PLy_quote_nullable(PyObject *self, PyObject *args); static PyObject *PLy_quote_ident(PyObject *self, PyObject *args); @@ -57,13 +57,13 @@ static PyMethodDef PLy_methods[] = { /* * logging methods */ - {"debug", PLy_debug, METH_VARARGS, NULL}, - {"log", PLy_log, METH_VARARGS, NULL}, - {"info", PLy_info, METH_VARARGS, NULL}, - {"notice", PLy_notice, METH_VARARGS, NULL}, - {"warning", PLy_warning, METH_VARARGS, NULL}, - {"error", PLy_error, METH_VARARGS, NULL}, - {"fatal", PLy_fatal, METH_VARARGS, NULL}, + {"debug", (PyCFunction) PLy_debug, METH_VARARGS|METH_KEYWORDS, NULL}, + {"log", (PyCFunction) PLy_log, METH_VARARGS|METH_KEYWORDS, NULL}, + {"info", (PyCFunction) PLy_info, METH_VARARGS|METH_KEYWORDS, NULL}, + {"notice", (PyCFunction) PLy_notice, METH_VARARGS|METH_KEYWORDS, NULL}, + {"warning", (PyCFunction) PLy_warning, METH_VARARGS|METH_KEYWORDS, NULL}, + {"error", (PyCFunction) PLy_error, METH_VARARGS|METH_KEYWORDS, NULL}, + {"fatal", (PyCFunction) PLy_fatal, METH_VARARGS|METH_KEYWORDS, NULL}, /* * create a stored plan @@ -271,48 +271,49 @@ PLy_generate_spi_exceptions(PyObject *mod, PyObject *base) * the python interface to the elog function * don't confuse these with PLy_elog */ -static PyObject *PLy_output(volatile int, PyObject *, PyObject *); +static PyObject *PLy_output(volatile int level, PyObject *self, + PyObject *args, PyObject *kw); static PyObject * -PLy_debug(PyObject *self, PyObject *args) +PLy_debug(PyObject *self, PyObject *args, PyObject *kw) { - return PLy_output(DEBUG2, self, args); + return PLy_output(DEBUG2, self, args, kw); } static PyObject * -PLy_log(PyObject *self, PyObject *args) +PLy_log(PyObject *self, PyObject *args, PyObject *kw) { - return PLy_output(LOG, self, args); + return PLy_output(LOG, self, args, kw); } static PyObject * -PLy_info(PyObject *self, PyObject *args) +PLy_info(PyObject *self, PyObject *args, PyObject *kw) { - return PLy_output(INFO, self, args); + return PLy_output(INFO, self, args, kw); } static PyObject * -PLy_notice(PyObject *self, PyObject *args) +PLy_notice(PyObject *self, PyObject *args, PyObject *kw) { - return PLy_output(NOTICE, self, args); + return PLy_output(NOTICE, self, args, kw); } static PyObject * -PLy_warning(PyObject *self, PyObject *args) +PLy_warning(PyObject *self, PyObject *args, PyObject *kw) { - return PLy_output(WARNING, self, args); + return PLy_output(WARNING, self, args, kw); } static PyObject * -PLy_error(PyObject *self, PyObject *args) +PLy_error(PyObject *self, PyObject *args, PyObject *kw) { - return PLy_output(ERROR, self, args); + return PLy_output(ERROR, self, args, kw); } static PyObject * -PLy_fatal(PyObject *self, PyObject *args) +PLy_fatal(PyObject *self, PyObject *args, PyObject *kw) { - return PLy_output(FATAL, self, args); + return PLy_output(FATAL, self, args, kw); } static PyObject * @@ -368,12 +369,45 @@ PLy_quote_ident(PyObject *self, PyObject *args) return ret; } +/* enforce cast of object to string */ +static char * +object_to_string(PyObject *obj) +{ + if (obj) + { + PyObject *so = PyObject_Str(obj); + + if (so != NULL) + { + char *str; + + str = pstrdup(PyString_AsString(so)); + Py_DECREF(so); + + return str; + } + } + + return NULL; +} + static PyObject * -PLy_output(volatile int level, PyObject *self, PyObject *args) +PLy_output(volatile int level, PyObject *self, PyObject *args, PyObject *kw) { - PyObject *volatile so; - char *volatile sv; - volatile MemoryContext oldcontext; + int sqlstate = 0; + char *volatile sqlstatestr = NULL; + char *volatile message = NULL; + char *volatile detail = NULL; + char *volatile hint = NULL; + char *volatile column = NULL; + char *volatile constraint = NULL; + char *volatile datatype = NULL; + char *volatile table = NULL; + char *volatile schema = NULL; + MemoryContext oldcontext ; + PyObject *key, *value; + PyObject *volatile so; + Py_ssize_t pos = 0; if (PyTuple_Size(args) == 1) { @@ -389,40 +423,118 @@ PLy_output(volatile int level, PyObject *self, PyObject *args) } else so = PyObject_Str(args); - if (so == NULL || ((sv = PyString_AsString(so)) == NULL)) + + if (so == NULL || ((message = pstrdup(PyString_AsString(so))) == NULL)) { level = ERROR; - sv = dgettext(TEXTDOMAIN, "could not parse error message in plpy.elog"); + message = dgettext(TEXTDOMAIN, "could not parse error message in plpy.elog"); + } + + Py_XDECREF(so); + + if (kw != NULL) + { + while (PyDict_Next(kw, &pos, &key, &value)) + { + char *keyword = PyString_AsString(key); + + if (strcmp(keyword, "message") == 0) + { + /* the message should not be overwriten */ + if (PyTuple_Size(args) != 0) + PLy_elog(ERROR, "the message is already specified"); + + pfree(message); + message = object_to_string(value); + } + else if (strcmp(keyword, "detail") == 0) + detail = object_to_string(value); + else if (strcmp(keyword, "hint") == 0) + hint = object_to_string(value); + else if (strcmp(keyword, "sqlstate") == 0) + sqlstatestr = object_to_string(value); + else if (strcmp(keyword, "schema") == 0) + schema = object_to_string(value); + else if (strcmp(keyword, "table") == 0) + table = object_to_string(value); + else if (strcmp(keyword, "column") == 0) + column = object_to_string(value); + else if (strcmp(keyword, "datatype") == 0) + datatype = object_to_string(value); + else if (strcmp(keyword, "constraint") == 0) + constraint = object_to_string(value); + else + PLy_elog(ERROR, "'%s' is an invalid keyword argument for this function", + keyword); + } + } + + if (sqlstatestr != NULL) + { + if (strlen(sqlstatestr) != 5) + PLy_elog(ERROR, "invalid SQLSTATE code"); + + if (strspn(sqlstatestr, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != 5) + PLy_elog(ERROR, "invalid SQLSTATE code"); + + sqlstate = MAKE_SQLSTATE(sqlstatestr[0], + sqlstatestr[1], + sqlstatestr[2], + sqlstatestr[3], + sqlstatestr[4]); } oldcontext = CurrentMemoryContext; PG_TRY(); { - pg_verifymbstr(sv, strlen(sv), false); - elog(level, "%s", sv); + if (message != NULL) + pg_verifymbstr(message, strlen(message), false); + if (detail != NULL) + pg_verifymbstr(detail, strlen(detail), false); + if (hint != NULL) + pg_verifymbstr(hint, strlen(hint), false); + if (schema != NULL) + pg_verifymbstr(schema, strlen(schema), false); + if (table != NULL) + pg_verifymbstr(table, strlen(table), false); + if (column != NULL) + pg_verifymbstr(column, strlen(column), false); + if (datatype != NULL) + pg_verifymbstr(datatype, strlen(datatype), false); + if (constraint != NULL) + pg_verifymbstr(constraint, strlen(constraint), false); + + ereport(level, + ((sqlstate != 0) ? errcode(sqlstate) : 0, + (message != NULL) ? errmsg_internal("%s", message) : 0, + (detail != NULL) ? errdetail_internal("%s", detail) : 0, + (hint != NULL) ? errhint("%s", hint) : 0, + (column != NULL) ? + err_generic_string(PG_DIAG_COLUMN_NAME, column) : 0, + (constraint != NULL) ? + err_generic_string(PG_DIAG_CONSTRAINT_NAME, constraint) : 0, + (datatype != NULL) ? + err_generic_string(PG_DIAG_DATATYPE_NAME, datatype) : 0, + (table != NULL) ? + err_generic_string(PG_DIAG_TABLE_NAME, table) : 0, + (schema != NULL) ? + err_generic_string(PG_DIAG_SCHEMA_NAME, schema) : 0)); } PG_CATCH(); { - ErrorData *edata; + ErrorData *edata; MemoryContextSwitchTo(oldcontext); edata = CopyErrorData(); FlushErrorState(); - /* - * Note: If sv came from PyString_AsString(), it points into storage - * owned by so. So free so after using sv. - */ - Py_XDECREF(so); + PLy_exception_set_with_details(PLy_exc_error, edata); + FreeErrorData(edata); - /* Make Python raise the exception */ - PLy_exception_set(PLy_exc_error, "%s", edata->message); return NULL; } PG_END_TRY(); - Py_XDECREF(so); - /* * return a legal object so the interpreter will continue on its merry way */ |