- FreeExecutorState(epqstate);
-
- epq->estate = NULL;
- epq->planstate = NULL;
-}
-
-/*
- * ExecGetActivePlanTree --- get the active PlanState tree from a QueryDesc
- *
- * Ordinarily this is just the one mentioned in the QueryDesc, but if we
- * are looking at a row returned by the EvalPlanQual machinery, we need
- * to look at the subsidiary state instead.
- */
-PlanState *
-ExecGetActivePlanTree(QueryDesc *queryDesc)
-{
- EState *estate = queryDesc->estate;
-
- if (estate && estate->es_useEvalPlan && estate->es_evalPlanQual != NULL)
- return estate->es_evalPlanQual->planstate;
- else
- return queryDesc->planstate;
-}
-
-
-/*
- * Support for SELECT INTO (a/k/a CREATE TABLE AS)
- *
- * We implement SELECT INTO by diverting SELECT's normal output with
- * a specialized DestReceiver type.
- */
-
-typedef struct
-{
- DestReceiver pub; /* publicly-known function pointers */
- EState *estate; /* EState we are working with */
- Relation rel; /* Relation to write to */
- int hi_options; /* heap_insert performance options */
- BulkInsertState bistate; /* bulk insert state */
-} DR_intorel;
-
-/*
- * OpenIntoRel --- actually create the SELECT INTO target relation
- *
- * This also replaces QueryDesc->dest with the special DestReceiver for
- * SELECT INTO. We assume that the correct result tuple type has already
- * been placed in queryDesc->tupDesc.
- */
-static void
-OpenIntoRel(QueryDesc *queryDesc)
-{
- IntoClause *into = queryDesc->plannedstmt->intoClause;
- EState *estate = queryDesc->estate;
- Relation intoRelationDesc;
- char *intoName;
- Oid namespaceId;
- Oid tablespaceId;
- Datum reloptions;
- AclResult aclresult;
- Oid intoRelationId;
- TupleDesc tupdesc;
- DR_intorel *myState;
- static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
-
- Assert(into);
-
- /*
- * Check consistency of arguments
- */
- if (into->onCommit != ONCOMMIT_NOOP && !into->rel->istemp)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
- errmsg("ON COMMIT can only be used on temporary tables")));
-
- /*
- * Find namespace to create in, check its permissions
- */
- intoName = into->rel->relname;
- namespaceId = RangeVarGetCreationNamespace(into->rel);
-
- aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
- ACL_CREATE);
- if (aclresult != ACLCHECK_OK)
- aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
- get_namespace_name(namespaceId));
-
- /*
- * Select tablespace to use. If not specified, use default tablespace
- * (which may in turn default to database's default).
- */
- if (into->tableSpaceName)
- {
- tablespaceId = get_tablespace_oid(into->tableSpaceName);
- if (!OidIsValid(tablespaceId))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("tablespace \"%s\" does not exist",
- into->tableSpaceName)));
- }
- else
- {
- tablespaceId = GetDefaultTablespace(into->rel->istemp);
- /* note InvalidOid is OK in this case */
- }
-
- /* Check permissions except when using the database's default space */
- if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
- {
- AclResult aclresult;
-
- aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(),
- ACL_CREATE);
-
- if (aclresult != ACLCHECK_OK)
- aclcheck_error(aclresult, ACL_KIND_TABLESPACE,
- get_tablespace_name(tablespaceId));
- }
-
- /* Parse and validate any reloptions */
- reloptions = transformRelOptions((Datum) 0,
- into->options,
- NULL,
- validnsps,
- true,
- false);
- (void) heap_reloptions(RELKIND_RELATION, reloptions, true);
-
- /* Copy the tupdesc because heap_create_with_catalog modifies it */
- tupdesc = CreateTupleDescCopy(queryDesc->tupDesc);
-
- /* Now we can actually create the new relation */
- intoRelationId = heap_create_with_catalog(intoName,
- namespaceId,
- tablespaceId,
- InvalidOid,
- InvalidOid,
- GetUserId(),
- tupdesc,
- NIL,
- RELKIND_RELATION,
- false,
- true,
- 0,
- into->onCommit,
- reloptions,
- allowSystemTableMods);
-
- FreeTupleDesc(tupdesc);
-
- /*
- * Advance command counter so that the newly-created relation's catalog
- * tuples will be visible to heap_open.
- */
- CommandCounterIncrement();
-
- /*
- * If necessary, create a TOAST table for the INTO relation. Note that
- * AlterTableCreateToastTable ends with CommandCounterIncrement(), so that
- * the TOAST table will be visible for insertion.
- */
- reloptions = transformRelOptions((Datum) 0,
- into->options,
- "toast",
- validnsps,
- true,
- false);
-
- (void) heap_reloptions(RELKIND_TOASTVALUE, reloptions, true);
-
- AlterTableCreateToastTable(intoRelationId, InvalidOid, reloptions, false);
-
- /*
- * And open the constructed table for writing.
- */
- intoRelationDesc = heap_open(intoRelationId, AccessExclusiveLock);
-
- /*
- * Now replace the query's DestReceiver with one for SELECT INTO
- */
- queryDesc->dest = CreateDestReceiver(DestIntoRel);
- myState = (DR_intorel *) queryDesc->dest;
- Assert(myState->pub.mydest == DestIntoRel);
- myState->estate = estate;
- myState->rel = intoRelationDesc;
-
- /*
- * We can skip WAL-logging the insertions, unless PITR is in use. We can
- * skip the FSM in any case.
- */
- myState->hi_options = HEAP_INSERT_SKIP_FSM |
- (XLogArchivingActive() ? 0 : HEAP_INSERT_SKIP_WAL);
- myState->bistate = GetBulkInsertState();
-
- /* Not using WAL requires rd_targblock be initially invalid */
- Assert(intoRelationDesc->rd_targblock == InvalidBlockNumber);
-}
-
-/*
- * CloseIntoRel --- clean up SELECT INTO at ExecutorEnd time
- */
-static void
-CloseIntoRel(QueryDesc *queryDesc)
-{
- DR_intorel *myState = (DR_intorel *) queryDesc->dest;
-
- /* OpenIntoRel might never have gotten called */
- if (myState && myState->pub.mydest == DestIntoRel && myState->rel)
- {
- FreeBulkInsertState(myState->bistate);
-
- /* If we skipped using WAL, must heap_sync before commit */
- if (myState->hi_options & HEAP_INSERT_SKIP_WAL)
- heap_sync(myState->rel);
-
- /* close rel, but keep lock until commit */
- heap_close(myState->rel, NoLock);
-
- myState->rel = NULL;
- }
-}
-
-/*
- * CreateIntoRelDestReceiver -- create a suitable DestReceiver object
- */
-DestReceiver *
-CreateIntoRelDestReceiver(void)
-{
- DR_intorel *self = (DR_intorel *) palloc0(sizeof(DR_intorel));
-
- self->pub.receiveSlot = intorel_receive;
- self->pub.rStartup = intorel_startup;
- self->pub.rShutdown = intorel_shutdown;
- self->pub.rDestroy = intorel_destroy;
- self->pub.mydest = DestIntoRel;
-
- /* private fields will be set by OpenIntoRel */
-
- return (DestReceiver *) self;
-}
-
-/*
- * intorel_startup --- executor startup
- */
-static void
-intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
-{
- /* no-op */
-}
-
-/*
- * intorel_receive --- receive one tuple
- */
-static void
-intorel_receive(TupleTableSlot *slot, DestReceiver *self)
-{
- DR_intorel *myState = (DR_intorel *) self;
- HeapTuple tuple;
-
- /*
- * get the heap tuple out of the tuple table slot, making sure we have a
- * writable copy
- */
- tuple = ExecMaterializeSlot(slot);
-
- /*
- * force assignment of new OID (see comments in ExecInsert)
- */
- if (myState->rel->rd_rel->relhasoids)
- HeapTupleSetOid(tuple, InvalidOid);
-
- heap_insert(myState->rel,
- tuple,
- myState->estate->es_output_cid,
- myState->hi_options,
- myState->bistate);
-
- /* We know this is a newly created relation, so there are no indexes */
-
- IncrAppended();
-}
-
-/*
- * intorel_shutdown --- executor end
- */
-static void
-intorel_shutdown(DestReceiver *self)
-{
- /* no-op */
-}