aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/executor/execMain.c20
-rw-r--r--src/test/regress/expected/select_into.out25
-rw-r--r--src/test/regress/sql/select_into.sql15
3 files changed, 55 insertions, 5 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 54df18d3c79..569d0ba7ade 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -2445,6 +2445,7 @@ typedef struct
{
DestReceiver pub; /* publicly-known function pointers */
EState *estate; /* EState we are working with */
+ DestReceiver *origdest; /* QueryDesc's original receiver */
Relation rel; /* Relation to write to */
int hi_options; /* heap_insert performance options */
BulkInsertState bistate; /* bulk insert state */
@@ -2651,12 +2652,14 @@ OpenIntoRel(QueryDesc *queryDesc)
/*
* Now replace the query's DestReceiver with one for SELECT INTO
*/
- queryDesc->dest = CreateDestReceiver(DestIntoRel);
- myState = (DR_intorel *) queryDesc->dest;
+ myState = (DR_intorel *) CreateDestReceiver(DestIntoRel);
Assert(myState->pub.mydest == DestIntoRel);
myState->estate = estate;
+ myState->origdest = queryDesc->dest;
myState->rel = intoRelationDesc;
+ queryDesc->dest = (DestReceiver *) myState;
+
/*
* We can skip WAL-logging the insertions, unless PITR or streaming
* replication is in use. We can skip the FSM in any case.
@@ -2677,8 +2680,11 @@ CloseIntoRel(QueryDesc *queryDesc)
{
DR_intorel *myState = (DR_intorel *) queryDesc->dest;
- /* OpenIntoRel might never have gotten called */
- if (myState && myState->pub.mydest == DestIntoRel && myState->rel)
+ /*
+ * OpenIntoRel might never have gotten called, and we also want to guard
+ * against double destruction.
+ */
+ if (myState && myState->pub.mydest == DestIntoRel)
{
FreeBulkInsertState(myState->bistate);
@@ -2689,7 +2695,11 @@ CloseIntoRel(QueryDesc *queryDesc)
/* close rel, but keep lock until commit */
heap_close(myState->rel, NoLock);
- myState->rel = NULL;
+ /* restore the receiver belonging to executor's caller */
+ queryDesc->dest = myState->origdest;
+
+ /* might as well invoke my destructor */
+ intorel_destroy((DestReceiver *) myState);
}
}
diff --git a/src/test/regress/expected/select_into.out b/src/test/regress/expected/select_into.out
index 9ed4229b506..c8327f677ae 100644
--- a/src/test/regress/expected/select_into.out
+++ b/src/test/regress/expected/select_into.out
@@ -50,3 +50,28 @@ DETAIL: drop cascades to table selinto_schema.tmp1
drop cascades to table selinto_schema.tmp2
drop cascades to table selinto_schema.tmp3
DROP USER selinto_user;
+--
+-- CREATE TABLE AS/SELECT INTO as last command in a SQL function
+-- have been known to cause problems
+--
+CREATE FUNCTION make_table() RETURNS VOID
+AS $$
+ CREATE TABLE created_table AS SELECT * FROM int8_tbl;
+$$ LANGUAGE SQL;
+SELECT make_table();
+ make_table
+------------
+
+(1 row)
+
+SELECT * FROM created_table;
+ q1 | q2
+------------------+-------------------
+ 123 | 456
+ 123 | 4567890123456789
+ 4567890123456789 | 123
+ 4567890123456789 | 4567890123456789
+ 4567890123456789 | -4567890123456789
+(5 rows)
+
+DROP TABLE created_table;
diff --git a/src/test/regress/sql/select_into.sql b/src/test/regress/sql/select_into.sql
index 039d35cd34c..09d210bc6f9 100644
--- a/src/test/regress/sql/select_into.sql
+++ b/src/test/regress/sql/select_into.sql
@@ -52,3 +52,18 @@ RESET SESSION AUTHORIZATION;
DROP SCHEMA selinto_schema CASCADE;
DROP USER selinto_user;
+
+--
+-- CREATE TABLE AS/SELECT INTO as last command in a SQL function
+-- have been known to cause problems
+--
+CREATE FUNCTION make_table() RETURNS VOID
+AS $$
+ CREATE TABLE created_table AS SELECT * FROM int8_tbl;
+$$ LANGUAGE SQL;
+
+SELECT make_table();
+
+SELECT * FROM created_table;
+
+DROP TABLE created_table;