diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index 775eaa07da89c..607e51ded5b6b 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -39,6 +39,9 @@ #include "utils/rel.h" #include "utils/sampling.h" +#include +#include + PG_MODULE_MAGIC; /* Default CPU cost to start up a foreign query. */ @@ -74,7 +77,7 @@ typedef struct PgFdwRelationInfo bool use_remote_estimate; Cost fdw_startup_cost; Cost fdw_tuple_cost; - + /* Cached catalog information. */ ForeignTable *table; ForeignServer *server; @@ -154,6 +157,9 @@ typedef struct PgFdwScanState int fetch_ct_2; /* Min(# of fetches done, 2) */ bool eof_reached; /* true if last fetch reached EOF */ + /* Timing */ + struct timeval start_time; + /* working memory contexts */ MemoryContext batch_cxt; /* context holding current batch of tuples */ MemoryContext temp_cxt; /* context for per-tuple temporary data */ @@ -1019,7 +1025,10 @@ postgresIterateForeignScan(ForeignScanState *node) * cursor on the remote side. */ if (!fsstate->cursor_exists) + { + gettimeofday(&(fsstate->start_time), NULL); create_cursor(node); + } /* * Get some more tuples, if we've run out. @@ -1116,7 +1125,15 @@ postgresEndForeignScan(ForeignScanState *node) /* Close the cursor if open, to prevent accumulation of cursors */ if (fsstate->cursor_exists) + { + struct timeval end_time; + double secs; + gettimeofday(&end_time, NULL); + secs = 1000 * end_time.tv_sec + end_time.tv_usec/1000.0; + secs -= 1000 * (fsstate->start_time).tv_sec + (fsstate->start_time).tv_usec/1000.0; + elog(DEBUG1, "FDW Query Duration: %.3lf ms", secs); close_cursor(fsstate->conn, fsstate->cursor_number); + } /* Release remote connection */ ReleaseConnection(fsstate->conn); diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index feeff9e864f4a..12baae50f43ad 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -189,7 +189,6 @@ static const char *backend_options = "--single -F -O -c search_path=pg_catalog - static const char *subdirs[] = { "global", - "pg_xlog", "pg_xlog/archive_status", "pg_clog", "pg_commit_ts", @@ -199,6 +198,7 @@ static const char *subdirs[] = { "pg_snapshots", "pg_subtrans", "pg_twophase", + "pg_multixact", "pg_multixact/members", "pg_multixact/offsets", "base", @@ -236,7 +236,6 @@ static FILE *popen_check(const char *command, const char *mode); static void exit_nicely(void); static char *get_id(void); static char *get_encoding_id(char *encoding_name); -static bool mkdatadir(const char *subdir); static void set_input(char **dest, char *filename); static void check_input(char *path); static void write_version_file(char *extrapath); @@ -276,7 +275,7 @@ void setup_locale_encoding(void); void setup_signals(void); void setup_text_search(void); void create_data_directory(void); -void create_xlog_symlink(void); +void create_xlog_or_symlink(void); void warn_on_mount_point(int error); void initialize_data_directory(void); @@ -924,29 +923,6 @@ find_matching_ts_config(const char *lc_type) } -/* - * make the data directory (or one of its subdirectories if subdir is not NULL) - */ -static bool -mkdatadir(const char *subdir) -{ - char *path; - - if (subdir) - path = psprintf("%s/%s", pg_data, subdir); - else - path = pg_strdup(pg_data); - - if (pg_mkdir_p(path, S_IRWXU) == 0) - return true; - - fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"), - progname, path, strerror(errno)); - - return false; -} - - /* * set name of given input file variable under data directory */ @@ -3134,8 +3110,12 @@ create_data_directory(void) pg_data); fflush(stdout); - if (!mkdatadir(NULL)) + if (pg_mkdir_p(pg_data, S_IRWXU) != 0) + { + fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"), + progname, pg_data, strerror(errno)); exit_nicely(); + } else check_ok(); @@ -3186,13 +3166,17 @@ create_data_directory(void) } +/* Create transaction log directory, and symlink if required */ void -create_xlog_symlink(void) +create_xlog_or_symlink(void) { - /* Create transaction log symlink, if required */ + char *subdirloc; + + /* form name of the place for the subdirectory or symlink */ + subdirloc = psprintf("%s/pg_xlog", pg_data); + if (strcmp(xlog_dir, "") != 0) { - char *linkloc; int ret; /* clean up xlog directory name, check it's absolute */ @@ -3265,22 +3249,30 @@ create_xlog_symlink(void) exit_nicely(); } - /* form name of the place where the symlink must go */ - linkloc = psprintf("%s/pg_xlog", pg_data); - #ifdef HAVE_SYMLINK - if (symlink(xlog_dir, linkloc) != 0) + if (symlink(xlog_dir, subdirloc) != 0) { fprintf(stderr, _("%s: could not create symbolic link \"%s\": %s\n"), - progname, linkloc, strerror(errno)); + progname, subdirloc, strerror(errno)); exit_nicely(); } #else fprintf(stderr, _("%s: symlinks are not supported on this platform")); exit_nicely(); #endif - free(linkloc); } + else + { + /* Without -X option, just make the subdirectory normally */ + if (mkdir(subdirloc, S_IRWXU) < 0) + { + fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"), + progname, subdirloc, strerror(errno)); + exit_nicely(); + } + } + + free(subdirloc); } @@ -3311,16 +3303,30 @@ initialize_data_directory(void) create_data_directory(); - create_xlog_symlink(); + create_xlog_or_symlink(); - /* Create required subdirectories */ + /* Create required subdirectories (other than pg_xlog) */ printf(_("creating subdirectories ... ")); fflush(stdout); - for (i = 0; i < (sizeof(subdirs) / sizeof(char *)); i++) + for (i = 0; i < lengthof(subdirs); i++) { - if (!mkdatadir(subdirs[i])) + char *path; + + path = psprintf("%s/%s", pg_data, subdirs[i]); + + /* + * The parent directory already exists, so we only need mkdir() not + * pg_mkdir_p() here, which avoids some failure modes; cf bug #13853. + */ + if (mkdir(path, S_IRWXU) < 0) + { + fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"), + progname, path, strerror(errno)); exit_nicely(); + } + + free(path); } check_ok(); diff --git a/src/include/port/atomics/arch-x86.h b/src/include/port/atomics/arch-x86.h index 168a49c79345a..3e77f3fa811ec 100644 --- a/src/include/port/atomics/arch-x86.h +++ b/src/include/port/atomics/arch-x86.h @@ -67,7 +67,7 @@ typedef struct pg_atomic_uint32 /* * It's too complicated to write inline asm for 64bit types on 32bit and the - * 468 can't do it. + * 486 can't do it. */ #ifdef __x86_64__ #define PG_HAVE_ATOMIC_U64_SUPPORT diff --git a/src/pl/plpython/expected/README b/src/pl/plpython/expected/README index 5bf93668da5d4..b8905633770ed 100644 --- a/src/pl/plpython/expected/README +++ b/src/pl/plpython/expected/README @@ -1,6 +1,7 @@ Guide to alternative expected files: plpython_error_0.out Python 2.4 and older +plpython_error_5.out Python 3.5 and newer plpython_unicode.out server encoding != SQL_ASCII plpython_unicode_3.out server encoding == SQL_ASCII diff --git a/src/pl/plpython/expected/plpython_error_5.out b/src/pl/plpython/expected/plpython_error_5.out new file mode 100644 index 0000000000000..fcd944cfa2130 --- /dev/null +++ b/src/pl/plpython/expected/plpython_error_5.out @@ -0,0 +1,428 @@ +-- 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 plpython3u; +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 plpython3u; +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 plpython3u; +SELECT sql_syntax_error(); +ERROR: spiexceptions.SyntaxError: syntax error at or near "syntax" +LINE 1: syntax error + ^ +QUERY: syntax error +CONTEXT: Traceback (most recent call last): + PL/Python function "sql_syntax_error", line 1, in + plpy.execute("syntax error") +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 plpython3u; +SELECT exception_index_invalid('test'); +ERROR: IndexError: list index out of range +CONTEXT: Traceback (most recent call last): + PL/Python function "exception_index_invalid", line 1, in + return args[1] +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 plpython3u; +SELECT exception_index_invalid_nested(); +ERROR: spiexceptions.UndefinedFunction: 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: Traceback (most recent call last): + PL/Python function "exception_index_invalid_nested", line 1, in + rv = plpy.execute("SELECT test5('foo')") +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 plpython3u; +SELECT invalid_type_uncaught('rick'); +ERROR: spiexceptions.UndefinedObject: type "test" does not exist +CONTEXT: Traceback (most recent call last): + PL/Python function "invalid_type_uncaught", line 3, in + SD["plan"] = plpy.prepare(q, [ "test" ]) +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 as ex: + plpy.notice(str(ex)) + return None +rv = plpy.execute(SD["plan"], [ a ]) +if len(rv): + return rv[0]["fname"] +return None +' + LANGUAGE plpython3u; +SELECT invalid_type_caught('rick'); +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 as ex: + plpy.error(str(ex)) +rv = plpy.execute(SD["plan"], [ a ]) +if len(rv): + return rv[0]["fname"] +return None +' + LANGUAGE plpython3u; +SELECT invalid_type_reraised('rick'); +ERROR: plpy.Error: type "test" does not exist +CONTEXT: Traceback (most recent call last): + PL/Python function "invalid_type_reraised", line 6, in + plpy.error(str(ex)) +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 plpython3u; +SELECT valid_type('rick'); + valid_type +------------ + +(1 row) + +/* error in nested functions to get a traceback +*/ +CREATE FUNCTION nested_error() RETURNS text + AS +'def fun1(): + plpy.error("boom") + +def fun2(): + fun1() + +def fun3(): + fun2() + +fun3() +return "not reached" +' + LANGUAGE plpython3u; +SELECT nested_error(); +ERROR: plpy.Error: boom +CONTEXT: Traceback (most recent call last): + PL/Python function "nested_error", line 10, in + fun3() + PL/Python function "nested_error", line 8, in fun3 + fun2() + PL/Python function "nested_error", line 5, in fun2 + fun1() + PL/Python function "nested_error", line 2, in fun1 + plpy.error("boom") +PL/Python function "nested_error" +/* raising plpy.Error is just like calling plpy.error +*/ +CREATE FUNCTION nested_error_raise() RETURNS text + AS +'def fun1(): + raise plpy.Error("boom") + +def fun2(): + fun1() + +def fun3(): + fun2() + +fun3() +return "not reached" +' + LANGUAGE plpython3u; +SELECT nested_error_raise(); +ERROR: plpy.Error: boom +CONTEXT: Traceback (most recent call last): + PL/Python function "nested_error_raise", line 10, in + fun3() + PL/Python function "nested_error_raise", line 8, in fun3 + fun2() + PL/Python function "nested_error_raise", line 5, in fun2 + fun1() + PL/Python function "nested_error_raise", line 2, in fun1 + raise plpy.Error("boom") +PL/Python function "nested_error_raise" +/* using plpy.warning should not produce a traceback +*/ +CREATE FUNCTION nested_warning() RETURNS text + AS +'def fun1(): + plpy.warning("boom") + +def fun2(): + fun1() + +def fun3(): + fun2() + +fun3() +return "you''ve been warned" +' + LANGUAGE plpython3u; +SELECT nested_warning(); +WARNING: boom +CONTEXT: PL/Python function "nested_warning" + nested_warning +-------------------- + you've been warned +(1 row) + +/* AttributeError at toplevel used to give segfaults with the traceback +*/ +CREATE FUNCTION toplevel_attribute_error() RETURNS void AS +$$ +plpy.nonexistent +$$ LANGUAGE plpython3u; +SELECT toplevel_attribute_error(); +ERROR: AttributeError: module 'plpy' has no attribute 'nonexistent' +CONTEXT: Traceback (most recent call last): + PL/Python function "toplevel_attribute_error", line 2, in + plpy.nonexistent +PL/Python function "toplevel_attribute_error" +/* Calling PL/Python functions from SQL and vice versa should not lose context. + */ +CREATE OR REPLACE FUNCTION python_traceback() RETURNS void AS $$ +def first(): + second() + +def second(): + third() + +def third(): + plpy.execute("select sql_error()") + +first() +$$ LANGUAGE plpython3u; +CREATE OR REPLACE FUNCTION sql_error() RETURNS void AS $$ +begin + select 1/0; +end +$$ LANGUAGE plpgsql; +CREATE OR REPLACE FUNCTION python_from_sql_error() RETURNS void AS $$ +begin + select python_traceback(); +end +$$ LANGUAGE plpgsql; +CREATE OR REPLACE FUNCTION sql_from_python_error() RETURNS void AS $$ +plpy.execute("select sql_error()") +$$ LANGUAGE plpython3u; +SELECT python_traceback(); +ERROR: spiexceptions.DivisionByZero: division by zero +CONTEXT: Traceback (most recent call last): + PL/Python function "python_traceback", line 11, in + first() + PL/Python function "python_traceback", line 3, in first + second() + PL/Python function "python_traceback", line 6, in second + third() + PL/Python function "python_traceback", line 9, in third + plpy.execute("select sql_error()") +PL/Python function "python_traceback" +SELECT sql_error(); +ERROR: division by zero +CONTEXT: SQL statement "select 1/0" +PL/pgSQL function sql_error() line 3 at SQL statement +SELECT python_from_sql_error(); +ERROR: spiexceptions.DivisionByZero: division by zero +CONTEXT: Traceback (most recent call last): + PL/Python function "python_traceback", line 11, in + first() + PL/Python function "python_traceback", line 3, in first + second() + PL/Python function "python_traceback", line 6, in second + third() + PL/Python function "python_traceback", line 9, in third + plpy.execute("select sql_error()") +PL/Python function "python_traceback" +SQL statement "select python_traceback()" +PL/pgSQL function python_from_sql_error() line 3 at SQL statement +SELECT sql_from_python_error(); +ERROR: spiexceptions.DivisionByZero: division by zero +CONTEXT: Traceback (most recent call last): + PL/Python function "sql_from_python_error", line 2, in + plpy.execute("select sql_error()") +PL/Python function "sql_from_python_error" +/* check catching specific types of exceptions + */ +CREATE TABLE specific ( + i integer PRIMARY KEY +); +CREATE FUNCTION specific_exception(i integer) RETURNS void AS +$$ +from plpy import spiexceptions +try: + plpy.execute("insert into specific values (%s)" % (i or "NULL")); +except spiexceptions.NotNullViolation as e: + plpy.notice("Violated the NOT NULL constraint, sqlstate %s" % e.sqlstate) +except spiexceptions.UniqueViolation as e: + plpy.notice("Violated the UNIQUE constraint, sqlstate %s" % e.sqlstate) +$$ LANGUAGE plpython3u; +SELECT specific_exception(2); + specific_exception +-------------------- + +(1 row) + +SELECT specific_exception(NULL); +NOTICE: Violated the NOT NULL constraint, sqlstate 23502 +CONTEXT: PL/Python function "specific_exception" + specific_exception +-------------------- + +(1 row) + +SELECT specific_exception(2); +NOTICE: Violated the UNIQUE constraint, sqlstate 23505 +CONTEXT: PL/Python function "specific_exception" + specific_exception +-------------------- + +(1 row) + +/* SPI errors in PL/Python functions should preserve the SQLSTATE value + */ +CREATE FUNCTION python_unique_violation() RETURNS void AS $$ +plpy.execute("insert into specific values (1)") +plpy.execute("insert into specific values (1)") +$$ LANGUAGE plpython3u; +CREATE FUNCTION catch_python_unique_violation() RETURNS text AS $$ +begin + begin + perform python_unique_violation(); + exception when unique_violation then + return 'ok'; + end; + return 'not reached'; +end; +$$ language plpgsql; +SELECT catch_python_unique_violation(); + catch_python_unique_violation +------------------------------- + ok +(1 row) + +/* manually starting subtransactions - a bad idea + */ +CREATE FUNCTION manual_subxact() RETURNS void AS $$ +plpy.execute("savepoint save") +plpy.execute("create table foo(x integer)") +plpy.execute("rollback to save") +$$ LANGUAGE plpython3u; +SELECT manual_subxact(); +ERROR: plpy.SPIError: SPI_execute failed: SPI_ERROR_TRANSACTION +CONTEXT: Traceback (most recent call last): + PL/Python function "manual_subxact", line 2, in + plpy.execute("savepoint save") +PL/Python function "manual_subxact" +/* same for prepared plans + */ +CREATE FUNCTION manual_subxact_prepared() RETURNS void AS $$ +save = plpy.prepare("savepoint save") +rollback = plpy.prepare("rollback to save") +plpy.execute(save) +plpy.execute("create table foo(x integer)") +plpy.execute(rollback) +$$ LANGUAGE plpython3u; +SELECT manual_subxact_prepared(); +ERROR: plpy.SPIError: SPI_execute_plan failed: SPI_ERROR_TRANSACTION +CONTEXT: Traceback (most recent call last): + PL/Python function "manual_subxact_prepared", line 4, in + plpy.execute(save) +PL/Python function "manual_subxact_prepared" +/* raising plpy.spiexception.* from python code should preserve sqlstate + */ +CREATE FUNCTION plpy_raise_spiexception() RETURNS void AS $$ +raise plpy.spiexceptions.DivisionByZero() +$$ LANGUAGE plpython3u; +DO $$ +BEGIN + SELECT plpy_raise_spiexception(); +EXCEPTION WHEN division_by_zero THEN + -- NOOP +END +$$ LANGUAGE plpgsql; +/* setting a custom sqlstate should be handled + */ +CREATE FUNCTION plpy_raise_spiexception_override() RETURNS void AS $$ +exc = plpy.spiexceptions.DivisionByZero() +exc.sqlstate = 'SILLY' +raise exc +$$ LANGUAGE plpython3u; +DO $$ +BEGIN + SELECT plpy_raise_spiexception_override(); +EXCEPTION WHEN SQLSTATE 'SILLY' THEN + -- NOOP +END +$$ LANGUAGE plpgsql; diff --git a/src/pl/plpython/expected/plpython_subtransaction.out b/src/pl/plpython/expected/plpython_subtransaction.out index ced4682440e23..c7bf6ccd42f2a 100644 --- a/src/pl/plpython/expected/plpython_subtransaction.out +++ b/src/pl/plpython/expected/plpython_subtransaction.out @@ -19,7 +19,7 @@ try: if what_error == "SPI": plpy.execute("INSERT INTO subtransaction_tbl VALUES ('oops')") elif what_error == "Python": - plpy.attribute_error + raise Exception("Python exception") except: exc = False subxact.__exit__(*sys.exc_info()) @@ -58,10 +58,10 @@ SELECT * FROM subtransaction_tbl; TRUNCATE subtransaction_tbl; SELECT subtransaction_test('Python'); -ERROR: AttributeError: 'module' object has no attribute 'attribute_error' +ERROR: Exception: Python exception CONTEXT: Traceback (most recent call last): PL/Python function "subtransaction_test", line 13, in - plpy.attribute_error + raise Exception("Python exception") PL/Python function "subtransaction_test" SELECT * FROM subtransaction_tbl; i @@ -78,7 +78,7 @@ with plpy.subtransaction(): if what_error == "SPI": plpy.execute("INSERT INTO subtransaction_tbl VALUES ('oops')") elif what_error == "Python": - plpy.attribute_error + raise Exception("Python exception") $$ LANGUAGE plpythonu; SELECT subtransaction_ctx_test(); subtransaction_ctx_test @@ -110,10 +110,10 @@ SELECT * FROM subtransaction_tbl; TRUNCATE subtransaction_tbl; SELECT subtransaction_ctx_test('Python'); -ERROR: AttributeError: 'module' object has no attribute 'attribute_error' +ERROR: Exception: Python exception CONTEXT: Traceback (most recent call last): PL/Python function "subtransaction_ctx_test", line 8, in - plpy.attribute_error + raise Exception("Python exception") PL/Python function "subtransaction_ctx_test" SELECT * FROM subtransaction_tbl; i diff --git a/src/pl/plpython/expected/plpython_subtransaction_0.out b/src/pl/plpython/expected/plpython_subtransaction_0.out index 6f4be556d548e..73bd7242bd882 100644 --- a/src/pl/plpython/expected/plpython_subtransaction_0.out +++ b/src/pl/plpython/expected/plpython_subtransaction_0.out @@ -19,7 +19,7 @@ try: if what_error == "SPI": plpy.execute("INSERT INTO subtransaction_tbl VALUES ('oops')") elif what_error == "Python": - plpy.attribute_error + raise Exception("Python exception") except: exc = False subxact.__exit__(*sys.exc_info()) @@ -58,10 +58,10 @@ SELECT * FROM subtransaction_tbl; TRUNCATE subtransaction_tbl; SELECT subtransaction_test('Python'); -ERROR: AttributeError: 'module' object has no attribute 'attribute_error' +ERROR: Exception: Python exception CONTEXT: Traceback (most recent call last): PL/Python function "subtransaction_test", line 13, in - plpy.attribute_error + raise Exception("Python exception") PL/Python function "subtransaction_test" SELECT * FROM subtransaction_tbl; i @@ -78,7 +78,7 @@ with plpy.subtransaction(): if what_error == "SPI": plpy.execute("INSERT INTO subtransaction_tbl VALUES ('oops')") elif what_error == "Python": - plpy.attribute_error + raise Exception("Python exception") $$ LANGUAGE plpythonu; ERROR: could not compile PL/Python function "subtransaction_ctx_test" DETAIL: SyntaxError: invalid syntax (line 3) diff --git a/src/pl/plpython/expected/plpython_subtransaction_5.out b/src/pl/plpython/expected/plpython_subtransaction_5.out index 4ca18357dc2f9..d1776200d2217 100644 --- a/src/pl/plpython/expected/plpython_subtransaction_5.out +++ b/src/pl/plpython/expected/plpython_subtransaction_5.out @@ -19,7 +19,7 @@ try: if what_error == "SPI": plpy.execute("INSERT INTO subtransaction_tbl VALUES ('oops')") elif what_error == "Python": - plpy.attribute_error + raise Exception("Python exception") except: exc = False subxact.__exit__(*sys.exc_info()) @@ -58,10 +58,10 @@ SELECT * FROM subtransaction_tbl; TRUNCATE subtransaction_tbl; SELECT subtransaction_test('Python'); -ERROR: AttributeError: 'module' object has no attribute 'attribute_error' +ERROR: Exception: Python exception CONTEXT: Traceback (most recent call last): PL/Python function "subtransaction_test", line 13, in - plpy.attribute_error + raise Exception("Python exception") PL/Python function "subtransaction_test" SELECT * FROM subtransaction_tbl; i @@ -78,7 +78,7 @@ with plpy.subtransaction(): if what_error == "SPI": plpy.execute("INSERT INTO subtransaction_tbl VALUES ('oops')") elif what_error == "Python": - plpy.attribute_error + raise Exception("Python exception") $$ LANGUAGE plpythonu; ERROR: could not compile PL/Python function "subtransaction_ctx_test" DETAIL: SyntaxError: invalid syntax (, line 3) diff --git a/src/pl/plpython/sql/plpython_subtransaction.sql b/src/pl/plpython/sql/plpython_subtransaction.sql index 9ad6377c7cd0c..3c188e3dd2dc2 100644 --- a/src/pl/plpython/sql/plpython_subtransaction.sql +++ b/src/pl/plpython/sql/plpython_subtransaction.sql @@ -23,7 +23,7 @@ try: if what_error == "SPI": plpy.execute("INSERT INTO subtransaction_tbl VALUES ('oops')") elif what_error == "Python": - plpy.attribute_error + raise Exception("Python exception") except: exc = False subxact.__exit__(*sys.exc_info()) @@ -53,7 +53,7 @@ with plpy.subtransaction(): if what_error == "SPI": plpy.execute("INSERT INTO subtransaction_tbl VALUES ('oops')") elif what_error == "Python": - plpy.attribute_error + raise Exception("Python exception") $$ LANGUAGE plpythonu; SELECT subtransaction_ctx_test();