From 32e7e7fa77bab73c9df8ea4bdb1fd65793451ff6 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 7 Jan 2016 15:22:01 -0500 Subject: [PATCH 1/5] Use plain mkdir() not pg_mkdir_p() to create subdirectories of PGDATA. When we're creating subdirectories of PGDATA during initdb, we know darn well that the parent directory exists (or should exist) and that the new subdirectory doesn't (or shouldn't). There is therefore no need to use anything more complicated than mkdir(). Using pg_mkdir_p() just opens us up to unexpected failure modes, such as the one exhibited in bug #13853 from Nuri Boardman. It's not very clear why pg_mkdir_p() went wrong there, but it is clear that we didn't need to be trying to create parent directories in the first place. We're not even saving any code, as proven by the fact that this patch nets out at minus five lines. Since this is a response to a field bug report, back-patch to all branches. --- src/bin/initdb/initdb.c | 49 ++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index feeff9e864f4a..862751e5e590c 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -199,6 +199,7 @@ static const char *subdirs[] = { "pg_snapshots", "pg_subtrans", "pg_twophase", + "pg_multixact", "pg_multixact/members", "pg_multixact/offsets", "base", @@ -236,7 +237,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); @@ -924,29 +924,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 +3111,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(); @@ -3317,10 +3298,24 @@ initialize_data_directory(void) 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(); From 506ef1d07f8b51e9799f6856b03a4317297a39cb Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 7 Jan 2016 18:20:57 -0500 Subject: [PATCH 2/5] Fix unobvious interaction between -X switch and subdirectory creation. Turns out the only reason initdb -X worked is that pg_mkdir_p won't whine if you point it at something that's a symlink to a directory. Otherwise, the attempt to create pg_xlog/ just like all the other subdirectories would have failed. Let's be a little more explicit about what's happening. Oversight in my patch for bug #13853 (mea culpa for not testing -X ...) --- src/bin/initdb/initdb.c | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index 862751e5e590c..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", @@ -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); @@ -3167,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 */ @@ -3246,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); } @@ -3292,9 +3303,9 @@ 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); From 6a1a44037b63e1c0e51dd2ca7374191c2f5362b1 Mon Sep 17 00:00:00 2001 From: Magnus Hagander Date: Fri, 8 Jan 2016 08:56:03 +0100 Subject: [PATCH 3/5] Fix typo in comment Tatsuro Yamada --- src/include/port/atomics/arch-x86.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From a66c1fcdd7e4291561c5cdebc1d02784050260e2 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 8 Jan 2016 11:39:28 -0500 Subject: [PATCH 4/5] PL/Python: Make tests pass with Python 3.5 The error message wording for AttributeError has changed in Python 3.5. For the plpython_error test, add a new expected file. In the plpython_subtransaction test, we didn't really care what the exception is, only that it is something coming from Python. So use a generic exception instead, which has a message that doesn't vary across versions. Back-patch of commit f16d52269a196f7f303abe3b978d95ade265f05f, which was previously back-patched into 9.2-9.4, but missed 9.5. --- src/pl/plpython/expected/README | 1 + src/pl/plpython/expected/plpython_error_5.out | 428 ++++++++++++++++++ .../expected/plpython_subtransaction.out | 12 +- .../expected/plpython_subtransaction_0.out | 8 +- .../expected/plpython_subtransaction_5.out | 8 +- .../plpython/sql/plpython_subtransaction.sql | 4 +- 6 files changed, 445 insertions(+), 16 deletions(-) create mode 100644 src/pl/plpython/expected/plpython_error_5.out 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(); From 021a3748ddbffdb42afca05c9ebde8c9862e4fba Mon Sep 17 00:00:00 2001 From: Paul Ramsey Date: Fri, 8 Jan 2016 11:35:45 -0800 Subject: [PATCH 5/5] Provide FDW query timing on DEBUG --- contrib/postgres_fdw/postgres_fdw.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) 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);