* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/executor/execAmi.c,v 1.95 2008/07/10 01:17:29 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execAmi.c,v 1.96 2008/07/26 19:15:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
return false;
}
}
-
-/*
- * ExecMayReturnRawTuples
- * Check whether a plan tree may return "raw" disk tuples (that is,
- * pointers to original data in disk buffers, as opposed to temporary
- * tuples constructed by projection steps). In the case of Append,
- * some subplans may return raw tuples and others projected tuples;
- * we return "true" if any of the returned tuples could be raw.
- *
- * This must be passed an already-initialized planstate tree, because we
- * need to look at the results of ExecAssignScanProjectionInfo().
- */
-bool
-ExecMayReturnRawTuples(PlanState *node)
-{
- /*
- * At a table scan node, we check whether ExecAssignScanProjectionInfo
- * decided to do projection or not. Most non-scan nodes always project
- * and so we can return "false" immediately. For nodes that don't project
- * but just pass up input tuples, we have to recursively examine the input
- * plan node.
- *
- * Note: Hash and Material are listed here because they sometimes return
- * an original input tuple, not a copy. But Sort and SetOp never return
- * an original tuple, so they can be treated like projecting nodes.
- */
- switch (nodeTag(node))
- {
- /* Table scan nodes */
- case T_SeqScanState:
- case T_IndexScanState:
- case T_BitmapHeapScanState:
- case T_TidScanState:
- if (node->ps_ProjInfo == NULL)
- return true;
- break;
-
- case T_SubqueryScanState:
- /* If not projecting, look at input plan */
- if (node->ps_ProjInfo == NULL)
- return ExecMayReturnRawTuples(((SubqueryScanState *) node)->subplan);
- break;
-
- /* Non-projecting nodes */
- case T_HashState:
- case T_MaterialState:
- case T_UniqueState:
- case T_LimitState:
- return ExecMayReturnRawTuples(node->lefttree);
-
- case T_AppendState:
- {
- AppendState *appendstate = (AppendState *) node;
- int j;
-
- for (j = 0; j < appendstate->as_nplans; j++)
- {
- if (ExecMayReturnRawTuples(appendstate->appendplans[j]))
- return true;
- }
- break;
- }
-
- /* All projecting node types come here */
- default:
- break;
- }
- return false;
-}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.310 2008/07/18 18:23:46 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.311 2008/07/26 19:15:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* Initialize the junk filter if needed. SELECT and INSERT queries need a
- * filter if there are any junk attrs in the tlist. INSERT and SELECT
- * INTO also need a filter if the plan may return raw disk tuples (else
- * heap_insert will be scribbling on the source relation!). UPDATE and
+ * filter if there are any junk attrs in the tlist. UPDATE and
* DELETE always need a filter, since there's always a junk 'ctid'
* attribute present --- no need to look first.
*/
break;
}
}
- if (!junk_filter_needed &&
- (operation == CMD_INSERT || estate->es_select_into) &&
- ExecMayReturnRawTuples(planstate))
- junk_filter_needed = true;
break;
case CMD_UPDATE:
case CMD_DELETE:
epqstate->es_result_relation_info = estate->es_result_relation_info;
epqstate->es_junkFilter = estate->es_junkFilter;
/* es_trig_target_relations must NOT be copied */
- epqstate->es_into_relation_descriptor = estate->es_into_relation_descriptor;
- epqstate->es_into_relation_use_wal = estate->es_into_relation_use_wal;
epqstate->es_param_list_info = estate->es_param_list_info;
if (estate->es_plannedstmt->nParamExec > 0)
epqstate->es_param_exec_vals = (ParamExecData *)
*
* We implement SELECT INTO by diverting SELECT's normal output with
* a specialized DestReceiver type.
- *
- * TODO: remove some of the INTO-specific cruft from EState, and keep
- * it in the DestReceiver instead.
*/
typedef struct
{
DestReceiver pub; /* publicly-known function pointers */
EState *estate; /* EState we are working with */
+ Relation rel; /* Relation to write to */
+ bool use_wal; /* do we need to WAL-log our writes? */
} DR_intorel;
/*
*/
intoRelationDesc = heap_open(intoRelationId, AccessExclusiveLock);
- /* use_wal off requires rd_targblock be initially invalid */
- Assert(intoRelationDesc->rd_targblock == InvalidBlockNumber);
-
- /*
- * We can skip WAL-logging the insertions, unless PITR is in use.
- */
- estate->es_into_relation_use_wal = XLogArchivingActive();
- estate->es_into_relation_descriptor = intoRelationDesc;
-
/*
* Now replace the query's DestReceiver with one for SELECT INTO
*/
myState = (DR_intorel *) queryDesc->dest;
Assert(myState->pub.mydest == DestIntoRel);
myState->estate = estate;
+
+ /*
+ * We can skip WAL-logging the insertions, unless PITR is in use.
+ */
+ myState->use_wal = XLogArchivingActive();
+ myState->rel = intoRelationDesc;
+
+ /* use_wal off requires rd_targblock be initially invalid */
+ Assert(intoRelationDesc->rd_targblock == InvalidBlockNumber);
}
/*
static void
CloseIntoRel(QueryDesc *queryDesc)
{
- EState *estate = queryDesc->estate;
+ DR_intorel *myState = (DR_intorel *) queryDesc->dest;
/* OpenIntoRel might never have gotten called */
- if (estate->es_into_relation_descriptor)
+ if (myState && myState->pub.mydest == DestIntoRel && myState->rel)
{
/* If we skipped using WAL, must heap_sync before commit */
- if (!estate->es_into_relation_use_wal)
- heap_sync(estate->es_into_relation_descriptor);
+ if (!myState->use_wal)
+ heap_sync(myState->rel);
/* close rel, but keep lock until commit */
- heap_close(estate->es_into_relation_descriptor, NoLock);
+ heap_close(myState->rel, NoLock);
- estate->es_into_relation_descriptor = NULL;
+ myState->rel = NULL;
}
}
* CreateIntoRelDestReceiver -- create a suitable DestReceiver object
*
* Since CreateDestReceiver doesn't accept the parameters we'd need,
- * we just leave the private fields empty here. OpenIntoRel will
+ * we just leave the private fields zeroed here. OpenIntoRel will
* fill them in.
*/
DestReceiver *
CreateIntoRelDestReceiver(void)
{
- DR_intorel *self = (DR_intorel *) palloc(sizeof(DR_intorel));
+ DR_intorel *self = (DR_intorel *) palloc0(sizeof(DR_intorel));
self->pub.receiveSlot = intorel_receive;
self->pub.rStartup = intorel_startup;
self->pub.rDestroy = intorel_destroy;
self->pub.mydest = DestIntoRel;
- self->estate = NULL;
-
return (DestReceiver *) self;
}
intorel_receive(TupleTableSlot *slot, DestReceiver *self)
{
DR_intorel *myState = (DR_intorel *) self;
- EState *estate = myState->estate;
HeapTuple tuple;
- tuple = ExecCopySlotTuple(slot);
+ /*
+ * get the heap tuple out of the tuple table slot, making sure we have a
+ * writable copy
+ */
+ tuple = ExecMaterializeSlot(slot);
- heap_insert(estate->es_into_relation_descriptor,
+ heap_insert(myState->rel,
tuple,
- estate->es_output_cid,
- estate->es_into_relation_use_wal,
+ myState->estate->es_output_cid,
+ myState->use_wal,
false); /* never any point in using FSM */
/* We know this is a newly created relation, so there are no indexes */
- heap_freetuple(tuple);
-
IncrAppended();
}