Hi

>>> But in my opinion this discussion shouldn't really even be about
>>> catching these things, most of the times you won't catch them and
>>> instead you'll let them go to Postgres. The discussion should be
>>> whether raise plpy.Error(...), plpy.raise_error, plpy.raise_info(,,,)
>>> etc. all with keyword argument support are a good PLPython interface
>>> to Postgres' ereport. I think they are.
>>>
>>
I removed from previous patch all OOP related changes. New patch contains
raise_xxxx functions only. This interface is new generation of previous
functions: info, notice, warning, error with keyword parameters interface.
I didn't changed older functions due keeping compatibility.

I spent lot of time with experiments how to merge PostgreSQL exception
system with Python exception system. But I didn't find a solution without
some design issues. These concepts(s) are too different (note: there are
two concepts: PostgreSQL levels and ANSI SQL SQLSTATE (class, subclass
codes).

I hope so raise_xxxx has benefit for PLPythonu users too. Currently users
has to use ugly workaround to raise rich PostgreSQL exception from Python.
With new function all available functionality related to PostgreSQL
exception can be used simply.

plpy.raise_warning("some doesn't work", detail = "user registration ... ")

This patch is reduced previous patch (no new features, no different
solution, no different code), so I use same entry in commitfest.

Regards

Pavel
diff --git a/doc/src/sgml/plpython.sgml b/doc/src/sgml/plpython.sgml
new file mode 100644
index 015bbad..705413e
*** a/doc/src/sgml/plpython.sgml
--- b/doc/src/sgml/plpython.sgml
*************** $$ LANGUAGE plpythonu;
*** 1367,1372 ****
--- 1367,1401 ----
    </para>
  
    <para>
+    The <literal>plpy</literal> module also provides the functions
+    <literal>plpy.raise_debug(<replaceable>args</>)</literal>,
+    <literal>plpy.raise_log(<replaceable>args</>)</literal>,
+    <literal>plpy.raise_info(<replaceable>args</>)</literal>,
+    <literal>plpy.raise_notice(<replaceable>args</>)</literal>,
+    <literal>plpy.raise_warning(<replaceable>args</>)</literal>,
+    <literal>plpy.raise_error(<replaceable>args</>)</literal>, and
+    <literal>plpy.raise_fatal(<replaceable>args</>)</literal>.<indexterm><primary>elog</><secondary>in PL/Python</></indexterm>
+    <function>plpy.raise_error</function> and
+    <function>plpy.raise_fatal</function> actually raise a Python exception
+    which, if uncaught, propagates out to the calling query, causing
+    the current transaction or subtransaction to be aborted.
+    <literal>raise plpy.Error(<replaceable>msg</>)</literal> and
+    <literal>raise plpy.Fatal(<replaceable>msg</>)</literal> are
+    equivalent to calling
+    <function>plpy.raise_error</function> and
+    <function>plpy.raise_fatal</function>, respectively.
+    The other functions only generate messages of different
+    priority levels.
+    Whether messages of a particular priority are reported to the client,
+    written to the server log, or both is controlled by the
+    <xref linkend="guc-log-min-messages"> and
+    <xref linkend="guc-client-min-messages"> configuration
+    variables. See <xref linkend="runtime-config"> for more information.
+    These functions allows to using keyword parameters:
+    <literal>[ <replaceable>message</replaceable> [, <replaceable>detail</replaceable> [, <replaceable>hint</replaceable> [, <replaceable>sqlstate</replaceable>  [, <replaceable>schema</replaceable>  [, <replaceable>table</replaceable>  [, <replaceable>column</replaceable>  [, <replaceable>datatype</replaceable>  [, <replaceable>constraint</replaceable> ]]]]]]]]]</literal>.
+   </para>
+ 
+   <para>
     Another set of utility functions are
     <literal>plpy.quote_literal(<replaceable>string</>)</literal>,
     <literal>plpy.quote_nullable(<replaceable>string</>)</literal>, and
diff --git a/src/pl/plpython/expected/plpython_test.out b/src/pl/plpython/expected/plpython_test.out
new file mode 100644
index 7b76faf..834b14a
*** a/src/pl/plpython/expected/plpython_test.out
--- b/src/pl/plpython/expected/plpython_test.out
*************** contents.sort()
*** 43,51 ****
  return ", ".join(contents)
  $$ LANGUAGE plpythonu;
  select module_contents();
!                                                                                module_contents                                                                                
! ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
!  Error, Fatal, SPIError, cursor, debug, error, execute, fatal, info, log, notice, prepare, quote_ident, quote_literal, quote_nullable, spiexceptions, subtransaction, warning
  (1 row)
  
  CREATE FUNCTION elog_test() RETURNS void
--- 43,51 ----
  return ", ".join(contents)
  $$ LANGUAGE plpythonu;
  select module_contents();
!                                                                                                                              module_contents                                                                                                                             
! -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
!  Error, Fatal, SPIError, cursor, debug, error, execute, fatal, info, log, notice, prepare, quote_ident, quote_literal, quote_nullable, raise_debug, raise_error, raise_fatal, raise_info, raise_log, raise_notice, raise_warning, spiexceptions, subtransaction, warning
  (1 row)
  
  CREATE FUNCTION elog_test() RETURNS void
*************** CONTEXT:  Traceback (most recent call la
*** 72,74 ****
--- 72,111 ----
    PL/Python function "elog_test", line 10, in <module>
      plpy.error('error')
  PL/Python function "elog_test"
+ CREATE FUNCTION elog_test2() RETURNS void
+ AS $$
+ plpy.raise_debug('debug','some detail')
+ plpy.raise_log('log','some detail')
+ plpy.raise_info('info','some detail')
+ plpy.raise_info()
+ plpy.raise_info('This is message text.',
+                     detail = 'This is detail text',
+                     hint = 'This is hint text.',
+                     sqlstate = 'XX000',
+                     schema = 'any info about schema',
+                     table = 'any info about table',
+                     column = 'any info about column',
+                     datatype = 'any info about datatype',
+                     constraint = 'any info about constraint')
+ plpy.raise_notice('notice','some detail')
+ plpy.raise_warning('warning','some detail')
+ plpy.raise_error('stop on error', 'some detail','some hint')
+ $$ LANGUAGE plpythonu;
+ SELECT elog_test2();
+ INFO:  info
+ DETAIL:  some detail
+ INFO:  missing error text
+ INFO:  This is message text.
+ DETAIL:  This is detail text
+ HINT:  This is hint text.
+ NOTICE:  notice
+ DETAIL:  some detail
+ WARNING:  warning
+ DETAIL:  some detail
+ ERROR:  plpy.SPIError: stop on error
+ DETAIL:  some detail
+ HINT:  some hint
+ CONTEXT:  Traceback (most recent call last):
+   PL/Python function "elog_test2", line 17, in <module>
+     plpy.raise_error('stop on error', 'some detail','some hint')
+ PL/Python function "elog_test2"
diff --git a/src/pl/plpython/plpy_elog.c b/src/pl/plpython/plpy_elog.c
new file mode 100644
index 15406d6..aea79db
*** a/src/pl/plpython/plpy_elog.c
--- b/src/pl/plpython/plpy_elog.c
*************** PyObject   *PLy_exc_spi_error = NULL;
*** 22,29 ****
  
  
  static void PLy_traceback(char **xmsg, char **tbmsg, int *tb_depth);
! static void PLy_get_spi_error_data(PyObject *exc, int *sqlerrcode, char **detail,
! 					   char **hint, char **query, int *position);
  static char *get_source_line(const char *src, int lineno);
  
  
--- 22,30 ----
  
  
  static void PLy_traceback(char **xmsg, char **tbmsg, int *tb_depth);
! static void PLy_get_spi_error_data(PyObject *exc, int *sqlerrcode, char **detail, char **hint, char **query, int *position,
! 						  char **schema_name, char **table_name, char **column_name,
! 						  char **datatype_name, char **constraint_name);
  static char *get_source_line(const char *src, int lineno);
  
  
*************** PLy_elog(int elevel, const char *fmt,...
*** 51,63 ****
  	char	   *hint = NULL;
  	char	   *query = NULL;
  	int			position = 0;
  
  	PyErr_Fetch(&exc, &val, &tb);
  	if (exc != NULL)
  	{
  		if (PyErr_GivenExceptionMatches(val, PLy_exc_spi_error))
! 			PLy_get_spi_error_data(val, &sqlerrcode, &detail, &hint, &query, &position);
! 		else if (PyErr_GivenExceptionMatches(val, PLy_exc_fatal))
  			elevel = FATAL;
  	}
  	PyErr_Restore(exc, val, tb);
--- 52,72 ----
  	char	   *hint = NULL;
  	char	   *query = NULL;
  	int			position = 0;
+ 	char	   *schema_name = NULL;
+ 	char	   *table_name = NULL;
+ 	char	   *column_name = NULL;
+ 	char	   *datatype_name = NULL;
+ 	char	   *constraint_name = NULL;
  
  	PyErr_Fetch(&exc, &val, &tb);
  	if (exc != NULL)
  	{
  		if (PyErr_GivenExceptionMatches(val, PLy_exc_spi_error))
! 			PLy_get_spi_error_data(val, &sqlerrcode, &detail, &hint, &query, &position,
! 						&schema_name, &table_name, &column_name,
! 						&datatype_name, &constraint_name);
! 
! 		if (PyErr_GivenExceptionMatches(val, PLy_exc_fatal))
  			elevel = FATAL;
  	}
  	PyErr_Restore(exc, val, tb);
*************** PLy_elog(int elevel, const char *fmt,...
*** 103,109 ****
  				 (tb_depth > 0 && tbmsg) ? errcontext("%s", tbmsg) : 0,
  				 (hint) ? errhint("%s", hint) : 0,
  				 (query) ? internalerrquery(query) : 0,
! 				 (position) ? internalerrposition(position) : 0));
  	}
  	PG_CATCH();
  	{
--- 112,124 ----
  				 (tb_depth > 0 && tbmsg) ? errcontext("%s", tbmsg) : 0,
  				 (hint) ? errhint("%s", hint) : 0,
  				 (query) ? internalerrquery(query) : 0,
! 				 (position) ? internalerrposition(position) : 0,
! 				 (schema_name) ? err_generic_string(PG_DIAG_SCHEMA_NAME, schema_name) : 0,
! 				 (table_name) ? err_generic_string(PG_DIAG_TABLE_NAME, table_name) : 0,
! 				 (column_name) ? err_generic_string(PG_DIAG_COLUMN_NAME, column_name) : 0,
! 				 (datatype_name) ? err_generic_string(PG_DIAG_DATATYPE_NAME, datatype_name) : 0,
! 				 (constraint_name) ? err_generic_string(PG_DIAG_CONSTRAINT_NAME, constraint_name) : 0));
! 
  	}
  	PG_CATCH();
  	{
*************** PLy_get_spi_sqlerrcode(PyObject *exc, in
*** 365,371 ****
   * Extract the error data from a SPIError
   */
  static void
! PLy_get_spi_error_data(PyObject *exc, int *sqlerrcode, char **detail, char **hint, char **query, int *position)
  {
  	PyObject   *spidata = NULL;
  
--- 380,388 ----
   * Extract the error data from a SPIError
   */
  static void
! PLy_get_spi_error_data(PyObject *exc, int *sqlerrcode, char **detail, char **hint, char **query, int *position,
! 			char **schema_name, char **table_name, char **column_name,
! 			char **datatype_name, char **constraint_name)
  {
  	PyObject   *spidata = NULL;
  
*************** PLy_get_spi_error_data(PyObject *exc, in
*** 373,379 ****
  
  	if (spidata != NULL)
  	{
! 		PyArg_ParseTuple(spidata, "izzzi", sqlerrcode, detail, hint, query, position);
  	}
  	else
  	{
--- 390,398 ----
  
  	if (spidata != NULL)
  	{
! 		PyArg_ParseTuple(spidata, "izzzizzzzz", sqlerrcode, detail, hint, query, position,
! 						    schema_name, table_name, column_name,
! 						    datatype_name, constraint_name);
  	}
  	else
  	{
diff --git a/src/pl/plpython/plpy_plpymodule.c b/src/pl/plpython/plpy_plpymodule.c
new file mode 100644
index a44b7fb..a4cdada
*** a/src/pl/plpython/plpy_plpymodule.c
--- b/src/pl/plpython/plpy_plpymodule.c
*************** static PyObject *PLy_quote_literal(PyObj
*** 39,44 ****
--- 39,52 ----
  static PyObject *PLy_quote_nullable(PyObject *self, PyObject *args);
  static PyObject *PLy_quote_ident(PyObject *self, PyObject *args);
  
+ /* module functions with keyword argument support */
+ static PyObject *PLy_raise_debug(PyObject *self, PyObject *args, PyObject *kw);
+ static PyObject *PLy_raise_log(PyObject *self, PyObject *args, PyObject *kw);
+ static PyObject *PLy_raise_info(PyObject *self, PyObject *args, PyObject *kw);
+ static PyObject *PLy_raise_notice(PyObject *self, PyObject *args, PyObject *kw);
+ static PyObject *PLy_raise_warning(PyObject *self, PyObject *args, PyObject *kw);
+ static PyObject *PLy_raise_error(PyObject *self, PyObject *args, PyObject *kw);
+ static PyObject *PLy_raise_fatal(PyObject *self, PyObject *args, PyObject *kw);
  
  /* A list of all known exceptions, generated from backend/utils/errcodes.txt */
  typedef struct ExceptionMap
*************** static PyMethodDef PLy_methods[] = {
*** 66,71 ****
--- 74,90 ----
  	{"fatal", PLy_fatal, METH_VARARGS, NULL},
  
  	/*
+ 	 * rich login methods
+ 	 */
+ 	{"raise_debug", (PyCFunction) PLy_raise_debug, METH_VARARGS | METH_KEYWORDS, NULL},
+ 	{"raise_log", (PyCFunction) PLy_raise_log, METH_VARARGS | METH_KEYWORDS, NULL},
+ 	{"raise_info", (PyCFunction) PLy_raise_info, METH_VARARGS | METH_KEYWORDS, NULL},
+ 	{"raise_notice", (PyCFunction) PLy_raise_notice, METH_VARARGS | METH_KEYWORDS, NULL},
+ 	{"raise_warning", (PyCFunction) PLy_raise_warning, METH_VARARGS | METH_KEYWORDS, NULL},
+ 	{"raise_error", (PyCFunction) PLy_raise_error, METH_VARARGS | METH_KEYWORDS, NULL},
+ 	{"raise_fatal", (PyCFunction) PLy_raise_fatal, METH_VARARGS | METH_KEYWORDS, NULL},
+ 
+ 	/*
  	 * create a stored plan
  	 */
  	{"prepare", PLy_spi_prepare, METH_VARARGS, NULL},
*************** PLy_fatal(PyObject *self, PyObject *args
*** 315,320 ****
--- 334,386 ----
  	return PLy_output(FATAL, self, args);
  }
  
+ /*
+  * the Python interface for raise functions
+  */
+ static PyObject *PLy_output_kw(volatile int, PyObject *, PyObject *, PyObject *);
+ 
+ static PyObject *
+ PLy_raise_debug(PyObject *self, PyObject *args, PyObject *kw)
+ {
+ 	return PLy_output_kw(DEBUG2, self, args, kw);
+ }
+ 
+ static PyObject *
+ PLy_raise_log(PyObject *self, PyObject *args, PyObject *kw)
+ {
+ 	return PLy_output_kw(LOG, self, args, kw);
+ }
+ 
+ static PyObject *
+ PLy_raise_info(PyObject *self, PyObject *args, PyObject *kw)
+ {
+ 	return PLy_output_kw(INFO, self, args, kw);
+ }
+ 
+ static PyObject *
+ PLy_raise_notice(PyObject *self, PyObject *args, PyObject *kw)
+ {
+ 	return PLy_output_kw(NOTICE, self, args, kw);
+ }
+ 
+ static PyObject *
+ PLy_raise_warning(PyObject *self, PyObject *args, PyObject *kw)
+ {
+ 	return PLy_output_kw(WARNING, self, args, kw);
+ }
+ 
+ static PyObject *
+ PLy_raise_error(PyObject *self, PyObject *args, PyObject *kw)
+ {
+ 	return PLy_output_kw(ERROR, self, args, kw);
+ }
+ 
+ static PyObject *
+ PLy_raise_fatal(PyObject *self, PyObject *args, PyObject *kw)
+ {
+ 	return PLy_output_kw(FATAL, self, args, kw);
+ }
+ 
  static PyObject *
  PLy_quote_literal(PyObject *self, PyObject *args)
  {
*************** PLy_output(volatile int level, PyObject
*** 429,431 ****
--- 495,594 ----
  	Py_INCREF(Py_None);
  	return Py_None;
  }
+ 
+ static PyObject *
+ PLy_output_kw(volatile int level, PyObject *self, PyObject *args, PyObject *kw)
+ {
+ 	int sqlstate = 0;
+ 	const char *sqlstatestr = NULL;
+ 	const char *message = NULL;
+ 	const char *detail = NULL;
+ 	const char *hint = NULL;
+ 	const char *column = NULL;
+ 	const char *constraint = NULL;
+ 	const char *datatype = NULL;
+ 	const char *table = NULL;
+ 	const char *schema = NULL;
+ 	MemoryContext oldcontext ;
+ 
+ 	static char *kwlist[] = { "message", "detail", "hint",
+ 				  "sqlstate",
+ 				  "schema","table", "column",
+ 				  "datatype", "constraint",
+ 				  NULL };
+ 
+ 	if (!PyArg_ParseTupleAndKeywords(args, kw, "|sssssssss", kwlist,
+ 			 &message, &detail, &hint,
+ 			 &sqlstatestr,
+ 			 &schema, &table, &column,
+ 			 &datatype, &constraint))
+ 		return NULL;
+ 
+ 	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();
+ 	{
+ 		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;
+ 
+ 		MemoryContextSwitchTo(oldcontext);
+ 		edata = CopyErrorData();
+ 		FlushErrorState();
+ 
+ 		PLy_spi_exception_set(PLy_exc_spi_error, edata);
+ 		FreeErrorData(edata);
+ 		return NULL;
+ 	}
+ 	PG_END_TRY();
+ 
+ 	Py_INCREF(Py_None);
+ 	return Py_None;
+ }
diff --git a/src/pl/plpython/plpy_spi.c b/src/pl/plpython/plpy_spi.c
new file mode 100644
index 58e78ec..36ea728
*** a/src/pl/plpython/plpy_spi.c
--- b/src/pl/plpython/plpy_spi.c
***************
*** 30,36 ****
  static PyObject *PLy_spi_execute_query(char *query, long limit);
  static PyObject *PLy_spi_execute_plan(PyObject *ob, PyObject *list, long limit);
  static PyObject *PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status);
- static void PLy_spi_exception_set(PyObject *excclass, ErrorData *edata);
  
  
  /* prepare(query="select * from foo")
--- 30,35 ----
*************** PLy_spi_subtransaction_abort(MemoryConte
*** 546,554 ****
  
  /*
   * Raise a SPIError, passing in it more error details, like the
!  * internal query and error position.
   */
! static void
  PLy_spi_exception_set(PyObject *excclass, ErrorData *edata)
  {
  	PyObject   *args = NULL;
--- 545,553 ----
  
  /*
   * Raise a SPIError, passing in it more error details, like the
!  * internal query and error position, sqlcode, detail, hint, ..
   */
! void
  PLy_spi_exception_set(PyObject *excclass, ErrorData *edata)
  {
  	PyObject   *args = NULL;
*************** PLy_spi_exception_set(PyObject *excclass
*** 564,571 ****
  	if (!spierror)
  		goto failure;
  
! 	spidata = Py_BuildValue("(izzzi)", edata->sqlerrcode, edata->detail, edata->hint,
! 							edata->internalquery, edata->internalpos);
  	if (!spidata)
  		goto failure;
  
--- 563,572 ----
  	if (!spierror)
  		goto failure;
  
! 	spidata= Py_BuildValue("(izzzizzzzz)", edata->sqlerrcode, edata->detail, edata->hint,
! 							edata->internalquery, edata->internalpos,
! 							edata->schema_name, edata->table_name, edata->column_name,
! 							edata->datatype_name, edata->constraint_name);
  	if (!spidata)
  		goto failure;
  
diff --git a/src/pl/plpython/plpy_spi.h b/src/pl/plpython/plpy_spi.h
new file mode 100644
index b042794..f9c54b8
*** a/src/pl/plpython/plpy_spi.h
--- b/src/pl/plpython/plpy_spi.h
*************** extern void PLy_spi_subtransaction_begin
*** 22,25 ****
--- 22,28 ----
  extern void PLy_spi_subtransaction_commit(MemoryContext oldcontext, ResourceOwner oldowner);
  extern void PLy_spi_subtransaction_abort(MemoryContext oldcontext, ResourceOwner oldowner);
  
+ /* raise and fill SPIError */
+ extern void PLy_spi_exception_set(PyObject *excclass, ErrorData *edata);
+ 
  #endif   /* PLPY_SPI_H */
diff --git a/src/pl/plpython/sql/plpython_test.sql b/src/pl/plpython/sql/plpython_test.sql
new file mode 100644
index c8d5ef5..190ce23
*** a/src/pl/plpython/sql/plpython_test.sql
--- b/src/pl/plpython/sql/plpython_test.sql
*************** plpy.error('error')
*** 51,53 ****
--- 51,75 ----
  $$ LANGUAGE plpythonu;
  
  SELECT elog_test();
+ 
+ CREATE FUNCTION elog_test2() RETURNS void
+ AS $$
+ plpy.raise_debug('debug','some detail')
+ plpy.raise_log('log','some detail')
+ plpy.raise_info('info','some detail')
+ plpy.raise_info()
+ plpy.raise_info('This is message text.',
+                     detail = 'This is detail text',
+                     hint = 'This is hint text.',
+                     sqlstate = 'XX000',
+                     schema = 'any info about schema',
+                     table = 'any info about table',
+                     column = 'any info about column',
+                     datatype = 'any info about datatype',
+                     constraint = 'any info about constraint')
+ plpy.raise_notice('notice','some detail')
+ plpy.raise_warning('warning','some detail')
+ plpy.raise_error('stop on error', 'some detail','some hint')
+ $$ LANGUAGE plpythonu;
+ 
+ SELECT elog_test2();
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to