*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201101251
+#define CATALOG_VERSION_NO 201102011
#endif
DATA(insert ( "pltclu" f f "pltclu_call_handler" _null_ _null_ "$libdir/pltcl" _null_ ));
DATA(insert ( "plperl" t t "plperl_call_handler" "plperl_inline_handler" "plperl_validator" "$libdir/plperl" _null_ ));
DATA(insert ( "plperlu" f f "plperl_call_handler" "plperl_inline_handler" "plperl_validator" "$libdir/plperl" _null_ ));
-DATA(insert ( "plpythonu" f f "plpython_call_handler" "plpython_inline_handler" _null_ "$libdir/plpython" _null_ ));
-DATA(insert ( "plpython2u" f f "plpython_call_handler" "plpython_inline_handler" _null_ "$libdir/plpython2" _null_ ));
-DATA(insert ( "plpython3u" f f "plpython3_call_handler" "plpython3_inline_handler" _null_ "$libdir/plpython3" _null_ ));
+DATA(insert ( "plpythonu" f f "plpython_call_handler" "plpython_inline_handler" "plpython_validator" "$libdir/plpython" _null_ ));
+DATA(insert ( "plpython2u" f f "plpython_call_handler" "plpython_inline_handler" "plpython_validator" "$libdir/plpython2" _null_ ));
+DATA(insert ( "plpython3u" f f "plpython3_call_handler" "plpython3_inline_handler" "plpython3_validator" "$libdir/plpython3" _null_ ));
#endif /* PG_PLTEMPLATE_H */
Guide to alternative expected files:
+plpython_error_0.out Python 2.4 and older
+
plpython_unicode.out any version, when server encoding != SQL_ASCII and client encoding = UTF8; else ...
plpython_unicode_0.out any version, when server encoding != SQL_ASCII and client encoding != UTF8; else ...
plpython_unicode_2.out Python 2.2
-- test error handling, i forgot to restore Warn_restart in
-- the trigger handler once. the errors and subsequent core dump were
-- interesting.
+/* Flat out Python syntax error
+ */
+CREATE FUNCTION python_syntax_error() RETURNS text
+ AS
+'.syntaxerror'
+ LANGUAGE plpythonu;
+ERROR: could not compile PL/Python function "python_syntax_error"
+DETAIL: SyntaxError: invalid syntax (<string>, line 2)
+/* With check_function_bodies = false the function should get defined
+ * and the error reported when called
+ */
+SET check_function_bodies = false;
+CREATE FUNCTION python_syntax_error() RETURNS text
+ AS
+'.syntaxerror'
+ LANGUAGE plpythonu;
+SELECT python_syntax_error();
+ERROR: could not compile PL/Python function "python_syntax_error"
+DETAIL: SyntaxError: invalid syntax (<string>, line 2)
+/* Run the function twice to check if the hashtable entry gets cleaned up */
+SELECT python_syntax_error();
+ERROR: could not compile PL/Python function "python_syntax_error"
+DETAIL: SyntaxError: invalid syntax (<string>, line 2)
+RESET check_function_bodies;
/* Flat out syntax error
*/
CREATE FUNCTION sql_syntax_error() RETURNS text
--- /dev/null
+-- test error handling, i forgot to restore Warn_restart in
+-- the trigger handler once. the errors and subsequent core dump were
+-- interesting.
+/* Flat out Python syntax error
+ */
+CREATE FUNCTION python_syntax_error() RETURNS text
+ AS
+'.syntaxerror'
+ LANGUAGE plpythonu;
+ERROR: could not compile PL/Python function "python_syntax_error"
+DETAIL: SyntaxError: invalid syntax (line 2)
+/* With check_function_bodies = false the function should get defined
+ * and the error reported when called
+ */
+SET check_function_bodies = false;
+CREATE FUNCTION python_syntax_error() RETURNS text
+ AS
+'.syntaxerror'
+ LANGUAGE plpythonu;
+SELECT python_syntax_error();
+ERROR: could not compile PL/Python function "python_syntax_error"
+DETAIL: SyntaxError: invalid syntax (line 2)
+/* Run the function twice to check if the hashtable entry gets cleaned up */
+SELECT python_syntax_error();
+ERROR: could not compile PL/Python function "python_syntax_error"
+DETAIL: SyntaxError: invalid syntax (line 2)
+RESET check_function_bodies;
+/* Flat out syntax error
+ */
+CREATE FUNCTION sql_syntax_error() RETURNS text
+ AS
+'plpy.execute("syntax error")'
+ LANGUAGE plpythonu;
+SELECT sql_syntax_error();
+WARNING: plpy.SPIError: unrecognized error in PLy_spi_execute_query
+CONTEXT: PL/Python function "sql_syntax_error"
+ERROR: plpy.SPIError: syntax error at or near "syntax"
+LINE 1: syntax error
+ ^
+QUERY: syntax error
+CONTEXT: PL/Python function "sql_syntax_error"
+/* check the handling of uncaught python exceptions
+ */
+CREATE FUNCTION exception_index_invalid(text) RETURNS text
+ AS
+'return args[1]'
+ LANGUAGE plpythonu;
+SELECT exception_index_invalid('test');
+ERROR: IndexError: list index out of range
+CONTEXT: PL/Python function "exception_index_invalid"
+/* check handling of nested exceptions
+ */
+CREATE FUNCTION exception_index_invalid_nested() RETURNS text
+ AS
+'rv = plpy.execute("SELECT test5(''foo'')")
+return rv[0]'
+ LANGUAGE plpythonu;
+SELECT exception_index_invalid_nested();
+WARNING: plpy.SPIError: unrecognized error in PLy_spi_execute_query
+CONTEXT: PL/Python function "exception_index_invalid_nested"
+ERROR: plpy.SPIError: function test5(unknown) does not exist
+LINE 1: SELECT test5('foo')
+ ^
+HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+QUERY: SELECT test5('foo')
+CONTEXT: PL/Python function "exception_index_invalid_nested"
+/* a typo
+ */
+CREATE FUNCTION invalid_type_uncaught(a text) RETURNS text
+ AS
+'if "plan" not in SD:
+ q = "SELECT fname FROM users WHERE lname = $1"
+ SD["plan"] = plpy.prepare(q, [ "test" ])
+rv = plpy.execute(SD["plan"], [ a ])
+if len(rv):
+ return rv[0]["fname"]
+return None
+'
+ LANGUAGE plpythonu;
+SELECT invalid_type_uncaught('rick');
+WARNING: plpy.SPIError: unrecognized error in PLy_spi_prepare
+CONTEXT: PL/Python function "invalid_type_uncaught"
+ERROR: plpy.SPIError: type "test" does not exist
+CONTEXT: PL/Python function "invalid_type_uncaught"
+/* for what it's worth catch the exception generated by
+ * the typo, and return None
+ */
+CREATE FUNCTION invalid_type_caught(a text) RETURNS text
+ AS
+'if "plan" not in SD:
+ q = "SELECT fname FROM users WHERE lname = $1"
+ try:
+ SD["plan"] = plpy.prepare(q, [ "test" ])
+ except plpy.SPIError, ex:
+ plpy.notice(str(ex))
+ return None
+rv = plpy.execute(SD["plan"], [ a ])
+if len(rv):
+ return rv[0]["fname"]
+return None
+'
+ LANGUAGE plpythonu;
+SELECT invalid_type_caught('rick');
+WARNING: plpy.SPIError: unrecognized error in PLy_spi_prepare
+CONTEXT: PL/Python function "invalid_type_caught"
+NOTICE: type "test" does not exist
+CONTEXT: PL/Python function "invalid_type_caught"
+ invalid_type_caught
+---------------------
+
+(1 row)
+
+/* for what it's worth catch the exception generated by
+ * the typo, and reraise it as a plain error
+ */
+CREATE FUNCTION invalid_type_reraised(a text) RETURNS text
+ AS
+'if "plan" not in SD:
+ q = "SELECT fname FROM users WHERE lname = $1"
+ try:
+ SD["plan"] = plpy.prepare(q, [ "test" ])
+ except plpy.SPIError, ex:
+ plpy.error(str(ex))
+rv = plpy.execute(SD["plan"], [ a ])
+if len(rv):
+ return rv[0]["fname"]
+return None
+'
+ LANGUAGE plpythonu;
+SELECT invalid_type_reraised('rick');
+WARNING: plpy.SPIError: unrecognized error in PLy_spi_prepare
+CONTEXT: PL/Python function "invalid_type_reraised"
+ERROR: plpy.Error: type "test" does not exist
+CONTEXT: PL/Python function "invalid_type_reraised"
+/* no typo no messing about
+ */
+CREATE FUNCTION valid_type(a text) RETURNS text
+ AS
+'if "plan" not in SD:
+ SD["plan"] = plpy.prepare("SELECT fname FROM users WHERE lname = $1", [ "text" ])
+rv = plpy.execute(SD["plan"], [ a ])
+if len(rv):
+ return rv[0]["fname"]
+return None
+'
+ LANGUAGE plpythonu;
+SELECT valid_type('rick');
+ valid_type
+------------
+
+(1 row)
+
second out text, third out text) AS $$
return first + '_record_in_to_out';
$$ LANGUAGE plpythonu;
+ERROR: PL/Python functions cannot return type record
CREATE FUNCTION test_inout_params(first inout text) AS $$
return first + '_inout';
$$ LANGUAGE plpythonu;
-- this doesn't work yet :-(
SELECT * FROM test_in_out_params_multi('test_in');
-ERROR: PL/Python functions cannot return type record
+ERROR: function test_in_out_params_multi(unknown) does not exist
+LINE 1: SELECT * FROM test_in_out_params_multi('test_in');
+ ^
+HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SELECT * FROM test_inout_params('test_in');
first
---------------
CREATE FUNCTION test_type_conversion_array_record() RETURNS type_record[] AS $$
return [None]
$$ LANGUAGE plpythonu;
-SELECT * FROM test_type_conversion_array_record();
ERROR: PL/Python functions cannot return type type_record[]
DETAIL: PL/Python does not support conversion to arrays of row types.
+SELECT * FROM test_type_conversion_array_record();
+ERROR: function test_type_conversion_array_record() does not exist
+LINE 1: SELECT * FROM test_type_conversion_array_record();
+ ^
+HINT: No function matches the given name and argument types. You might need to add explicit type casts.
CREATE FUNCTION test_type_conversion_array_string() RETURNS text[] AS $$
return 'abc'
$$ LANGUAGE plpythonu;
CREATE FUNCTION test_type_conversion_array_record() RETURNS type_record[] AS $$
return [None]
$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_array_record();
ERROR: PL/Python functions cannot return type type_record[]
DETAIL: PL/Python does not support conversion to arrays of row types.
+SELECT * FROM test_type_conversion_array_record();
+ERROR: function test_type_conversion_array_record() does not exist
+LINE 1: SELECT * FROM test_type_conversion_array_record();
+ ^
+HINT: No function matches the given name and argument types. You might need to add explicit type casts.
CREATE FUNCTION test_type_conversion_array_string() RETURNS text[] AS $$
return 'abc'
$$ LANGUAGE plpython3u;
#if PY_MAJOR_VERSION >= 3
/* Use separate names to avoid clash in pg_pltemplate */
+#define plpython_validator plpython3_validator
#define plpython_call_handler plpython3_call_handler
#define plpython_inline_handler plpython3_inline_handler
#endif
/* exported functions */
+Datum plpython_validator(PG_FUNCTION_ARGS);
Datum plpython_call_handler(PG_FUNCTION_ARGS);
Datum plpython_inline_handler(PG_FUNCTION_ARGS);
void _PG_init(void);
+PG_FUNCTION_INFO_V1(plpython_validator);
PG_FUNCTION_INFO_V1(plpython_call_handler);
PG_FUNCTION_INFO_V1(plpython_inline_handler);
errcontext("while creating return value");
}
+static bool
+PLy_procedure_is_trigger(Form_pg_proc procStruct)
+{
+ return (procStruct->prorettype == TRIGGEROID ||
+ (procStruct->prorettype == OPAQUEOID &&
+ procStruct->pronargs == 0));
+}
+
+Datum
+plpython_validator(PG_FUNCTION_ARGS)
+{
+ Oid funcoid = PG_GETARG_OID(0);
+ HeapTuple tuple;
+ Form_pg_proc procStruct;
+ bool is_trigger;
+
+ if (!check_function_bodies)
+ {
+ PG_RETURN_VOID();
+ }
+
+ /* Get the new function's pg_proc entry */
+ tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for function %u", funcoid);
+ procStruct = (Form_pg_proc) GETSTRUCT(tuple);
+
+ is_trigger = PLy_procedure_is_trigger(procStruct);
+
+ ReleaseSysCache(tuple);
+
+ PLy_procedure_get(funcoid, is_trigger);
+
+ PG_RETURN_VOID();
+}
+
Datum
plpython_call_handler(PG_FUNCTION_ARGS)
{
-- the trigger handler once. the errors and subsequent core dump were
-- interesting.
+/* Flat out Python syntax error
+ */
+CREATE FUNCTION python_syntax_error() RETURNS text
+ AS
+'.syntaxerror'
+ LANGUAGE plpythonu;
+
+/* With check_function_bodies = false the function should get defined
+ * and the error reported when called
+ */
+SET check_function_bodies = false;
+
+CREATE FUNCTION python_syntax_error() RETURNS text
+ AS
+'.syntaxerror'
+ LANGUAGE plpythonu;
+
+SELECT python_syntax_error();
+/* Run the function twice to check if the hashtable entry gets cleaned up */
+SELECT python_syntax_error();
+
+RESET check_function_bodies;
+
/* Flat out syntax error
*/
CREATE FUNCTION sql_syntax_error() RETURNS text