summaryrefslogtreecommitdiff
path: root/src/pl/plpython/plpy_plpymodule.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pl/plpython/plpy_plpymodule.c')
-rw-r--r--src/pl/plpython/plpy_plpymodule.c206
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
*/