From 790d5bc9922d515f04b83182b1767a4eaa37cdb7 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Thu, 23 Jan 2003 05:10:41 +0000
Subject: [PATCH] Change CREATE TABLE AS / SELECT INTO to create the new table
 with OIDs, for backwards compatibility with pre-7.3 behavior.  Per discussion
 on pgsql-general and pgsql-hackers.

---
 src/backend/executor/execMain.c  | 131 ++++++++++++++++---------------
 src/backend/executor/execUtils.c |  24 ++++--
 src/include/nodes/execnodes.h    |   4 +-
 3 files changed, 89 insertions(+), 70 deletions(-)

diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 04aed372c00..e1178cd6a69 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -26,7 +26,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.198 2003/01/12 18:19:37 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.199 2003/01/23 05:10:37 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -450,6 +450,7 @@ InitPlan(QueryDesc *queryDesc)
 	PlanState  *planstate;
 	List	   *rangeTable;
 	Relation	intoRelationDesc;
+	bool		do_select_into;
 	TupleDesc	tupType;
 
 	/*
@@ -529,6 +530,26 @@ InitPlan(QueryDesc *queryDesc)
 		estate->es_result_relation_info = NULL;
 	}
 
+	/*
+	 * Detect whether we're doing SELECT INTO.  If so, set the force_oids
+	 * flag appropriately so that the plan tree will be initialized with
+	 * the correct tuple descriptors.
+	 */
+	do_select_into = false;
+
+	if (operation == CMD_SELECT &&
+		!parseTree->isPortal &&
+		parseTree->into != NULL)
+	{
+		do_select_into = true;
+		/*
+		 * For now, always create OIDs in SELECT INTO; this is for backwards
+		 * compatibility with pre-7.3 behavior.  Eventually we might want
+		 * to allow the user to choose.
+		 */
+		estate->es_force_oids = true;
+	}
+
 	/*
 	 * Have to lock relations selected for update
 	 */
@@ -687,79 +708,64 @@ InitPlan(QueryDesc *queryDesc)
 	}
 
 	/*
-	 * initialize the "into" relation
+	 * If doing SELECT INTO, initialize the "into" relation.  We must wait
+	 * till now so we have the "clean" result tuple type to create the
+	 * new table from.
 	 */
 	intoRelationDesc = (Relation) NULL;
 
-	if (operation == CMD_SELECT)
+	if (do_select_into)
 	{
-		if (!parseTree->isPortal)
-		{
-			/*
-			 * a select into table --- need to create the "into" table
-			 */
-			if (parseTree->into != NULL)
-			{
-				char	   *intoName;
-				Oid			namespaceId;
-				AclResult	aclresult;
-				Oid			intoRelationId;
-				TupleDesc	tupdesc;
+		char	   *intoName;
+		Oid			namespaceId;
+		AclResult	aclresult;
+		Oid			intoRelationId;
+		TupleDesc	tupdesc;
 
-				/*
-				 * find namespace to create in, check permissions
-				 */
-				intoName = parseTree->into->relname;
-				namespaceId = RangeVarGetCreationNamespace(parseTree->into);
+		/*
+		 * find namespace to create in, check permissions
+		 */
+		intoName = parseTree->into->relname;
+		namespaceId = RangeVarGetCreationNamespace(parseTree->into);
 
-				aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
-												  ACL_CREATE);
-				if (aclresult != ACLCHECK_OK)
-					aclcheck_error(aclresult,
-								   get_namespace_name(namespaceId));
+		aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
+										  ACL_CREATE);
+		if (aclresult != ACLCHECK_OK)
+			aclcheck_error(aclresult, get_namespace_name(namespaceId));
 
-				/*
-				 * have to copy tupType to get rid of constraints
-				 */
-				tupdesc = CreateTupleDescCopy(tupType);
-
-				/*
-				 * Formerly we forced the output table to have OIDs, but
-				 * as of 7.3 it will not have OIDs, because it's too late
-				 * here to change the tupdescs of the already-initialized
-				 * plan tree.  (Perhaps we could recurse and change them
-				 * all, but it's not really worth the trouble IMHO...)
-				 */
+		/*
+		 * have to copy tupType to get rid of constraints
+		 */
+		tupdesc = CreateTupleDescCopy(tupType);
 
-				intoRelationId =
-					heap_create_with_catalog(intoName,
-											 namespaceId,
-											 tupdesc,
-											 RELKIND_RELATION,
-											 false,
-											 ONCOMMIT_NOOP,
-											 allowSystemTableMods);
+		intoRelationId = heap_create_with_catalog(intoName,
+												  namespaceId,
+												  tupdesc,
+												  RELKIND_RELATION,
+												  false,
+												  ONCOMMIT_NOOP,
+												  allowSystemTableMods);
 
-				FreeTupleDesc(tupdesc);
+		FreeTupleDesc(tupdesc);
 
-				/*
-				 * Advance command counter so that the newly-created
-				 * relation's catalog tuples will be visible to heap_open.
-				 */
-				CommandCounterIncrement();
+		/*
+		 * 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.
-				 */
-				AlterTableCreateToastTable(intoRelationId, true);
+		/*
+		 * 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.
+		 */
+		AlterTableCreateToastTable(intoRelationId, true);
 
-				intoRelationDesc = heap_open(intoRelationId,
-											 AccessExclusiveLock);
-			}
-		}
+		/*
+		 * And open the constructed table for writing.
+		 */
+		intoRelationDesc = heap_open(intoRelationId, AccessExclusiveLock);
 	}
 
 	estate->es_into_relation_descriptor = intoRelationDesc;
@@ -1964,6 +1970,7 @@ EvalPlanQualStart(evalPlanQual *epq, EState *estate, evalPlanQual *priorepq)
 			palloc0(estate->es_topPlan->nParamExec * sizeof(ParamExecData));
 	epqstate->es_rowMark = estate->es_rowMark;
 	epqstate->es_instrument = estate->es_instrument;
+	epqstate->es_force_oids = estate->es_force_oids;
 	epqstate->es_topPlan = estate->es_topPlan;
 	/*
 	 * Each epqstate must have its own es_evTupleNull state, but
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 63eede22802..90bd8adf1ae 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.95 2003/01/12 04:03:34 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.96 2003/01/23 05:10:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -199,6 +199,7 @@ CreateExecutorState(void)
 	estate->es_rowMark = NIL;
 
 	estate->es_instrument = false;
+	estate->es_force_oids = false;
 
 	estate->es_exprcontexts = NIL;
 
@@ -424,7 +425,6 @@ ExecAssignResultTypeFromOuterPlan(PlanState *planstate)
 void
 ExecAssignResultTypeFromTL(PlanState *planstate)
 {
-	ResultRelInfo *ri;
 	bool		hasoid = false;
 	TupleDesc	tupDesc;
 
@@ -444,14 +444,24 @@ ExecAssignResultTypeFromTL(PlanState *planstate)
 	 * have to make the decision on a per-relation basis as we initialize
 	 * each of the child plans of the topmost Append plan.	So, this is
 	 * ugly but it works, for now ...
+	 *
+	 * SELECT INTO is also pretty grotty, because we don't yet have the
+	 * INTO relation's descriptor at this point; we have to look aside
+	 * at a flag set by InitPlan().
 	 */
-	ri = planstate->state->es_result_relation_info;
-	if (ri != NULL)
+	if (planstate->state->es_force_oids)
+		hasoid = true;
+	else
 	{
-		Relation	rel = ri->ri_RelationDesc;
+		ResultRelInfo *ri = planstate->state->es_result_relation_info;
 
-		if (rel != NULL)
-			hasoid = rel->rd_rel->relhasoids;
+		if (ri != NULL)
+		{
+			Relation	rel = ri->ri_RelationDesc;
+
+			if (rel != NULL)
+				hasoid = rel->rd_rel->relhasoids;
+		}
 	}
 
 	/*
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 2aa672b65ea..98c6f1ddfbd 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: execnodes.h,v 1.91 2003/01/12 04:03:34 tgl Exp $
+ * $Id: execnodes.h,v 1.92 2003/01/23 05:10:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -311,6 +311,8 @@ typedef struct EState
 	List	   *es_rowMark;		/* not good place, but there is no other */
 
 	bool		es_instrument;	/* true requests runtime instrumentation */
+	bool		es_force_oids;	/* true forces result tuples to have (space
+								 * for) OIDs --- used for SELECT INTO */
 
 	List	   *es_exprcontexts; /* List of ExprContexts within EState */
 
-- 
GitLab