summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane2014-05-07 18:25:11 +0000
committerTom Lane2014-05-07 18:25:11 +0000
commit04e5025be8bbe572e12b19c4ba9e2a8360b8ffe5 (patch)
treeb3ca927510db0f037f27feefe7cfe8670baedb59
parente2ce9aa27bf20eff2d991d0267a15ea5f7024cd7 (diff)
Fix failure to set ActiveSnapshot while rewinding a cursor.
ActiveSnapshot needs to be set when we call ExecutorRewind because some plan node types may execute user-defined functions during their ReScan calls (nodeLimit.c does so, at least). The wisdom of that is somewhat debatable, perhaps, but for now the simplest fix is to make sure the required context is valid. Failure to do this typically led to a null-pointer-dereference core dump, though it's possible that in more complex cases a function could be executed with the wrong snapshot leading to very subtle misbehavior. Per report from Leif Jensen. It's been broken for a long time, so back-patch to all active branches.
-rw-r--r--src/backend/tcop/pquery.c14
-rw-r--r--src/test/regress/expected/portals.out24
-rw-r--r--src/test/regress/sql/portals.sql11
3 files changed, 47 insertions, 2 deletions
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
index fa561a4861a..f9ed266c1ad 100644
--- a/src/backend/tcop/pquery.c
+++ b/src/backend/tcop/pquery.c
@@ -1661,6 +1661,9 @@ DoPortalRunFetch(Portal portal,
static void
DoPortalRewind(Portal portal)
{
+ QueryDesc *queryDesc;
+
+ /* Rewind holdStore, if we have one */
if (portal->holdStore)
{
MemoryContext oldcontext;
@@ -1669,8 +1672,15 @@ DoPortalRewind(Portal portal)
tuplestore_rescan(portal->holdStore);
MemoryContextSwitchTo(oldcontext);
}
- if (PortalGetQueryDesc(portal))
- ExecutorRewind(PortalGetQueryDesc(portal));
+
+ /* Rewind executor, if active */
+ queryDesc = PortalGetQueryDesc(portal);
+ if (queryDesc)
+ {
+ PushActiveSnapshot(queryDesc->snapshot);
+ ExecutorRewind(queryDesc);
+ PopActiveSnapshot();
+ }
portal->atStart = true;
portal->atEnd = false;
diff --git a/src/test/regress/expected/portals.out b/src/test/regress/expected/portals.out
index aafc6cf5294..462ad231c36 100644
--- a/src/test/regress/expected/portals.out
+++ b/src/test/regress/expected/portals.out
@@ -1261,3 +1261,27 @@ FETCH ALL FROM c1;
COMMIT;
DROP TABLE cursor;
+-- Check rewinding a cursor containing a stable function in LIMIT,
+-- per bug report in 8336843.9833.1399385291498.JavaMail.root@quick
+begin;
+create function nochange(int) returns int
+ as 'select $1 limit 1' language sql stable;
+declare c cursor for select * from int8_tbl limit nochange(3);
+fetch all from c;
+ q1 | q2
+------------------+------------------
+ 123 | 456
+ 123 | 4567890123456789
+ 4567890123456789 | 123
+(3 rows)
+
+move backward all in c;
+fetch all from c;
+ q1 | q2
+------------------+------------------
+ 123 | 456
+ 123 | 4567890123456789
+ 4567890123456789 | 123
+(3 rows)
+
+rollback;
diff --git a/src/test/regress/sql/portals.sql b/src/test/regress/sql/portals.sql
index 203e6577039..01c3b85da9a 100644
--- a/src/test/regress/sql/portals.sql
+++ b/src/test/regress/sql/portals.sql
@@ -473,3 +473,14 @@ UPDATE cursor SET a = 2;
FETCH ALL FROM c1;
COMMIT;
DROP TABLE cursor;
+
+-- Check rewinding a cursor containing a stable function in LIMIT,
+-- per bug report in 8336843.9833.1399385291498.JavaMail.root@quick
+begin;
+create function nochange(int) returns int
+ as 'select $1 limit 1' language sql stable;
+declare c cursor for select * from int8_tbl limit nochange(3);
+fetch all from c;
+move backward all in c;
+fetch all from c;
+rollback;