diff options
-rw-r--r-- | src/backend/executor/execMain.c | 20 | ||||
-rw-r--r-- | src/test/regress/expected/select_into.out | 25 | ||||
-rw-r--r-- | src/test/regress/sql/select_into.sql | 14 |
3 files changed, 54 insertions, 5 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index d69ca83187b..aa64ae7a670 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -2842,6 +2842,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 */ @@ -2999,12 +3000,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 is in use. We can * skip the FSM in any case. @@ -3025,8 +3028,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); @@ -3037,7 +3043,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 503efe04fc2..a71abf5b48d 100644 --- a/src/test/regress/expected/select_into.out +++ b/src/test/regress/expected/select_into.out @@ -11,3 +11,28 @@ SELECT * FROM onek2 WHERE onek2.unique1 < 2; DROP TABLE tmp1; +-- +-- 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 993c44b727d..5763c5e1842 100644 --- a/src/test/regress/sql/select_into.sql +++ b/src/test/regress/sql/select_into.sql @@ -16,3 +16,17 @@ SELECT * DROP TABLE tmp1; +-- +-- 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; |